diff --git a/cfgmgr/Makefile.am b/cfgmgr/Makefile.am index 685ab04407..09fda145fc 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 -bin_PROGRAMS = vlanmgrd teammgrd portmgrd intfmgrd buffermgrd vrfmgrd nbrmgrd vxlanmgrd sflowmgrd natmgrd coppmgrd tunnelmgrd macsecmgrd +bin_PROGRAMS = vlanmgrd teammgrd portmgrd intfmgrd buffermgrd vrfmgrd nbrmgrd vxlanmgrd sflowmgrd natmgrd coppmgrd tunnelmgrd macsecmgrd fabricmgrd cfgmgrdir = $(datadir)/swss @@ -46,6 +46,11 @@ portmgrd_CFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI) $(CFLA portmgrd_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI) $(CFLAGS_ASAN) portmgrd_LDADD = $(LDFLAGS_ASAN) $(COMMON_LIBS) $(SAIMETA_LIBS) +fabricmgrd_SOURCES = fabricmgrd.cpp fabricmgr.cpp $(COMMON_ORCH_SOURCE) shellcmd.h +fabricmgrd_CFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI) $(CFLAGS_ASAN) +fabricmgrd_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI) $(CFLAGS_ASAN) +fabricmgrd_LDADD = $(LDFLAGS_ASAN) $(COMMON_LIBS) $(SAIMETA_LIBS) + intfmgrd_SOURCES = intfmgrd.cpp intfmgr.cpp $(top_srcdir)/lib/subintf.cpp $(COMMON_ORCH_SOURCE) shellcmd.h intfmgrd_CFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI) $(CFLAGS_ASAN) intfmgrd_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI) $(CFLAGS_ASAN) @@ -110,6 +115,7 @@ natmgrd_LDADD += -lgcovpreload coppmgrd_LDADD += -lgcovpreload tunnelmgrd_LDADD += -lgcovpreload macsecmgrd_LDADD += -lgcovpreload +fabricmgrd_LDADD += -lgcovpreload endif if ASAN_ENABLED @@ -126,5 +132,6 @@ natmgrd_SOURCES += $(top_srcdir)/lib/asan.cpp coppmgrd_SOURCES += $(top_srcdir)/lib/asan.cpp tunnelmgrd_SOURCES += $(top_srcdir)/lib/asan.cpp macsecmgrd_SOURCES += $(top_srcdir)/lib/asan.cpp +fabricmgrd_SOURCES += $(top_srcdir)/lib/asan.cpp endif diff --git a/cfgmgr/fabricmgr.cpp b/cfgmgr/fabricmgr.cpp new file mode 100644 index 0000000000..bcbaa5726a --- /dev/null +++ b/cfgmgr/fabricmgr.cpp @@ -0,0 +1,119 @@ +#include "logger.h" +#include "dbconnector.h" +#include "producerstatetable.h" +#include "tokenize.h" +#include "ipprefix.h" +#include "fabricmgr.h" +#include "exec.h" +#include "shellcmd.h" +#include + +using namespace std; +using namespace swss; + +FabricMgr::FabricMgr(DBConnector *cfgDb, DBConnector *appDb, const vector &tableNames) : + Orch(cfgDb, tableNames), + m_cfgFabricMonitorTable(cfgDb, CFG_FABRIC_MONITOR_DATA_TABLE_NAME), + m_cfgFabricPortTable(cfgDb, CFG_FABRIC_MONITOR_PORT_TABLE_NAME), + m_appFabricMonitorTable(appDb, APP_FABRIC_MONITOR_DATA_TABLE_NAME), + m_appFabricPortTable(appDb, APP_FABRIC_MONITOR_PORT_TABLE_NAME) +{ +} + +void FabricMgr::doTask(Consumer &consumer) +{ + SWSS_LOG_ENTER(); + + auto table = consumer.getTableName(); + + auto it = consumer.m_toSync.begin(); + while (it != consumer.m_toSync.end()) + { + KeyOpFieldsValuesTuple t = it->second; + + string key = kfvKey(t); + string op = kfvOp(t); + + if (op == SET_COMMAND) + { + + string monErrThreshCrcCells, monErrThreshRxCells; + string monPollThreshRecovery, monPollThreshIsolation; + string isolateStatus; + string alias, lanes; + std::vector field_values; + string value; + + for (auto i : kfvFieldsValues(t)) + { + if (fvField(i) == "monErrThreshCrcCells") + { + monErrThreshCrcCells = fvValue(i); + writeConfigToAppDb(key, "monErrThreshCrcCells", monErrThreshCrcCells); + } + else if (fvField(i) == "monErrThreshRxCells") + { + monErrThreshRxCells = fvValue(i); + writeConfigToAppDb(key, "monErrThreshRxCells", monErrThreshRxCells); + } + else if (fvField(i) == "monPollThreshRecovery") + { + monPollThreshRecovery = fvValue(i); + writeConfigToAppDb(key, "monPollThreshRecovery", monPollThreshRecovery); + } + else if (fvField(i) == "monPollThreshIsolation") + { + monPollThreshIsolation = fvValue(i); + writeConfigToAppDb(key, "monPollThreshIsolation", monPollThreshIsolation); + } + else if (fvField(i) == "alias") + { + alias = fvValue(i); + writeConfigToAppDb(key, "alias", alias); + } + else if (fvField(i) == "lanes") + { + lanes = fvValue(i); + writeConfigToAppDb(key, "lanes", lanes); + } + else if (fvField(i) == "isolateStatus") + { + isolateStatus = fvValue(i); + writeConfigToAppDb(key, "isolateStatus", isolateStatus); + } + else + { + field_values.emplace_back(i); + } + } + + for (auto &entry : field_values) + { + writeConfigToAppDb(key, fvField(entry), fvValue(entry)); + } + + } + it = consumer.m_toSync.erase(it); + } +} + +bool FabricMgr::writeConfigToAppDb(const std::string &key, const std::string &field, const std::string &value) +{ + vector fvs; + FieldValueTuple fv(field, value); + fvs.push_back(fv); + if (key == "FABRIC_MONITOR_DATA") + { + m_appFabricMonitorTable.set(key, fvs); + SWSS_LOG_NOTICE("Write FABRIC_MONITOR:%s %s to %s", key.c_str(), field.c_str(), value.c_str()); + } + else + { + m_appFabricPortTable.set(key, fvs); + SWSS_LOG_NOTICE("Write FABRIC_PORT:%s %s to %s", key.c_str(), field.c_str(), value.c_str()); + } + + return true; +} + + diff --git a/cfgmgr/fabricmgr.h b/cfgmgr/fabricmgr.h new file mode 100644 index 0000000000..dbe2fd0d89 --- /dev/null +++ b/cfgmgr/fabricmgr.h @@ -0,0 +1,30 @@ +#pragma once + +#include "dbconnector.h" +#include "orch.h" +#include "producerstatetable.h" + +#include +#include +#include + +namespace swss { + + +class FabricMgr : public Orch +{ +public: + FabricMgr(DBConnector *cfgDb, DBConnector *appDb, const std::vector &tableNames); + + using Orch::doTask; +private: + Table m_cfgFabricMonitorTable; + Table m_cfgFabricPortTable; + Table m_appFabricMonitorTable; + Table m_appFabricPortTable; + + void doTask(Consumer &consumer); + bool writeConfigToAppDb(const std::string &alias, const std::string &field, const std::string &value); +}; + +} diff --git a/cfgmgr/fabricmgrd.cpp b/cfgmgr/fabricmgrd.cpp new file mode 100644 index 0000000000..3d0777e17c --- /dev/null +++ b/cfgmgr/fabricmgrd.cpp @@ -0,0 +1,73 @@ +#include +#include +#include +#include +#include + +#include "exec.h" +#include "fabricmgr.h" +#include "schema.h" +#include "select.h" + +using namespace std; +using namespace swss; + +/* select() function timeout retry time, in millisecond */ +#define SELECT_TIMEOUT 1000 + +int main(int argc, char **argv) +{ + Logger::linkToDbNative("fabricmgrd"); + SWSS_LOG_ENTER(); + + SWSS_LOG_NOTICE("--- Starting fabricmgrd ---"); + + try + { + vector cfg_fabric_tables = { + CFG_FABRIC_MONITOR_DATA_TABLE_NAME, + CFG_FABRIC_MONITOR_PORT_TABLE_NAME, + }; + + DBConnector cfgDb("CONFIG_DB", 0); + DBConnector appDb("APPL_DB", 0); + + FabricMgr fabricmgr(&cfgDb, &appDb, cfg_fabric_tables); + + // TODO: add tables in stateDB which interface depends on to monitor list + vector cfgOrchList = {&fabricmgr}; + + 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) + { + fabricmgr.doTask(); + continue; + } + + auto *c = (Executor *)sel; + c->execute(); + } + } + catch (const exception &e) + { + SWSS_LOG_ERROR("Runtime error: %s", e.what()); + } + return -1; +} + diff --git a/tests/test_fabric_port.py b/tests/test_fabric_port.py new file mode 100644 index 0000000000..a7ad9958b0 --- /dev/null +++ b/tests/test_fabric_port.py @@ -0,0 +1,48 @@ +from swsscommon import swsscommon +from dvslib.dvs_database import DVSDatabase + + +class TestVirtualChassis(object): + def test_voq_switch_fabric_link(self, vst): + """Test fabric link manual isolation commands in VOQ switch. + + By issuing config fabric port isolation command, the value + of isolateStatus field in config_db get changed. This test validates appl_db + updates of a fabric link isolateStatus as the value in config_db changed. + """ + + dvss = vst.dvss + for name in dvss.keys(): + dvs = dvss[name] + # Get the config info + config_db = dvs.get_config_db() + metatbl = config_db.get_entry("DEVICE_METADATA", "localhost") + + cfg_switch_type = metatbl.get("switch_type") + if cfg_switch_type == "fabric": + + # get config_db information + cdb = dvs.get_config_db() + + # set config_db to isolateStatus: True + cdb.update_entry("FABRIC_PORT", "Fabric1", {"isolateStatus": "True"}) + cdb.wait_for_field_match("FABRIC_PORT", "Fabric1", {"isolateStatus": "True"}) + + # check if appl_db value changes to isolateStatus: True + adb = dvs.get_app_db() + adb.wait_for_field_match("FABRIC_PORT_TABLE", "Fabric1", {"isolateStatus": "True"}) + + # cleanup + cdb.update_entry("FABRIC_PORT", "Fabric1", {"isolateStatus": "False"}) + cdb.wait_for_field_match("FABRIC_PORT", "Fabric1", {"isolateStatus": "False"}) + adb.wait_for_field_match("FABRIC_PORT_TABLE", "Fabric1", {"isolateStatus": "False"}) + else: + print( "We do not check switch type:", cfg_switch_type ) + + +# Add Dummy always-pass test at end as workaroud +# for issue when Flaky fail on final test it invokes module tear-down before retrying +def test_nonflaky_dummy(): + pass + +