From 13df5a98d4a6375a778b6216cff886a0c474aa9a Mon Sep 17 00:00:00 2001 From: Marian Pritsak Date: Wed, 19 Sep 2018 20:37:10 +0300 Subject: [PATCH] [cfgmgr]: Add vrfmgrd (#621) * [cfgmgr]: Add vrfmgrd vrfmgrd is responsible for VRF configuration in Linux It creates VRF-Lite device for every VRF entry in Config DB Signed-off-by: Marian Pritsak * Fix comments Signed-off-by: Marian Pritsak * [vrfmgrd]: Recover VRF info from linux after restart Signed-off-by: Marian Pritsak * [vrfmgrd]: Set Table ID range from 1001 to 2000 Signed-off-by: Marian Pritsak * Throw when cmd fails Signed-off-by: Marian Pritsak --- .gitignore | 1 + cfgmgr/Makefile.am | 6 +- cfgmgr/vrfmgr.cpp | 175 +++++++++++++++++++++++++++++++++++++++++++++ cfgmgr/vrfmgr.h | 34 +++++++++ cfgmgr/vrfmgrd.cpp | 89 +++++++++++++++++++++++ 5 files changed, 304 insertions(+), 1 deletion(-) create mode 100644 cfgmgr/vrfmgr.cpp create mode 100644 cfgmgr/vrfmgr.h create mode 100644 cfgmgr/vrfmgrd.cpp diff --git a/.gitignore b/.gitignore index 8bb5f10449ae..736b86b5a398 100644 --- a/.gitignore +++ b/.gitignore @@ -48,6 +48,7 @@ intfsyncd/intfsyncd cfgmgr/intfmgrd cfgmgr/vlanmgrd cfgmgr/buffermanager +cfgmgr/vrfmgrd neighsyncd/neighsyncd portsyncd/portsyncd orchagent/orchagent diff --git a/cfgmgr/Makefile.am b/cfgmgr/Makefile.am index 958514047711..96dfd73f3b3e 100644 --- a/cfgmgr/Makefile.am +++ b/cfgmgr/Makefile.am @@ -1,7 +1,7 @@ INCLUDES = -I $(top_srcdir) -I $(top_srcdir)/orchagent -I $(top_srcdir)/warmrestart CFLAGS_SAI = -I /usr/include/sai -bin_PROGRAMS = vlanmgrd portmgrd intfmgrd buffermgrd +bin_PROGRAMS = vlanmgrd portmgrd intfmgrd buffermgrd vrfmgrd if DEBUG DBGFLAGS = -ggdb -DDEBUG @@ -30,3 +30,7 @@ buffermgrd_CFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI) buffermgrd_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI) buffermgrd_LDADD = -lswsscommon +vrfmgrd_SOURCES = vrfmgrd.cpp vrfmgr.cpp $(top_srcdir)/orchagent/orch.cpp $(top_srcdir)/orchagent/request_parser.cpp shellcmd.h +vrfmgrd_CFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI) +vrfmgrd_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI) +vrfmgrd_LDADD = -lswsscommon diff --git a/cfgmgr/vrfmgr.cpp b/cfgmgr/vrfmgr.cpp new file mode 100644 index 000000000000..7b06213ec56c --- /dev/null +++ b/cfgmgr/vrfmgr.cpp @@ -0,0 +1,175 @@ +#include +#include "logger.h" +#include "dbconnector.h" +#include "producerstatetable.h" +#include "tokenize.h" +#include "ipprefix.h" +#include "vrfmgr.h" +#include "exec.h" +#include "shellcmd.h" + +#define VRF_TABLE_START 1001 +#define VRF_TABLE_END 2000 + +using namespace swss; + +VrfMgr::VrfMgr(DBConnector *cfgDb, DBConnector *appDb, DBConnector *stateDb, const vector &tableNames) : + Orch(cfgDb, tableNames) +{ + for (uint32_t i = VRF_TABLE_START; i < VRF_TABLE_END; i++) + { + m_freeTables.emplace(i); + } + + /* Get existing VRFs from Linux */ + stringstream cmd; + string res; + + cmd << IP_CMD << " -d link show type vrf"; + EXEC_WITH_ERROR_THROW(cmd.str(), res); + + enum IpShowRowType + { + LINK_ROW, + MAC_ROW, + DETAILS_ROW, + }; + + string vrfName; + uint32_t table; + IpShowRowType rowType = LINK_ROW; + const auto& rows = tokenize(res, '\n'); + for (const auto& row : rows) + { + const auto& items = tokenize(row, ' '); + switch(rowType) + { + case LINK_ROW: + vrfName = items[1]; + vrfName.pop_back(); + rowType = MAC_ROW; + break; + case MAC_ROW: + rowType = DETAILS_ROW; + break; + case DETAILS_ROW: + table = static_cast(stoul(items[6])); + m_vrfTableMap[vrfName] = table; + m_freeTables.erase(table); + rowType = LINK_ROW; + break; + } + } +} + +uint32_t VrfMgr::getFreeTable(void) +{ + SWSS_LOG_ENTER(); + + if (m_freeTables.empty()) + { + return 0; + } + + uint32_t table = *m_freeTables.begin(); + m_freeTables.erase(table); + + return table; +} + +void VrfMgr::recycleTable(uint32_t table) +{ + SWSS_LOG_ENTER(); + + m_freeTables.emplace(table); +} + +bool VrfMgr::delLink(const string& vrfName) +{ + SWSS_LOG_ENTER(); + + stringstream cmd; + string res; + + if (m_vrfTableMap.find(vrfName) == m_vrfTableMap.end()) + { + return false; + } + + cmd << IP_CMD << " link del " << vrfName; + EXEC_WITH_ERROR_THROW(cmd.str(), res); + + recycleTable(m_vrfTableMap[vrfName]); + m_vrfTableMap.erase(vrfName); + + return true; +} + +bool VrfMgr::setLink(const string& vrfName) +{ + SWSS_LOG_ENTER(); + + stringstream cmd; + string res; + + if (m_vrfTableMap.find(vrfName) != m_vrfTableMap.end()) + { + return true; + } + + uint32_t table = getFreeTable(); + if (table == 0) + { + return false; + } + + cmd << IP_CMD << " link add " << vrfName << " type vrf table " << table; + EXEC_WITH_ERROR_THROW(cmd.str(), res); + + m_vrfTableMap.emplace(vrfName, table); + + cmd.str(""); + cmd.clear(); + cmd << IP_CMD << " link set " << vrfName << " up"; + EXEC_WITH_ERROR_THROW(cmd.str(), res); + + return true; +} + +void VrfMgr::doTask(Consumer &consumer) +{ + SWSS_LOG_ENTER(); + + auto it = consumer.m_toSync.begin(); + while (it != consumer.m_toSync.end()) + { + KeyOpFieldsValuesTuple t = it->second; + auto vrfName = kfvKey(t); + + string op = kfvOp(t); + if (op == SET_COMMAND) + { + if (!setLink(vrfName)) + { + SWSS_LOG_ERROR("Failed to create vrf netdev %s", vrfName.c_str()); + } + + SWSS_LOG_NOTICE("Created vrf netdev %s", vrfName.c_str()); + } + else if (op == DEL_COMMAND) + { + if (!delLink(vrfName)) + { + SWSS_LOG_ERROR("Failed to remove vrf netdev %s", vrfName.c_str()); + } + + SWSS_LOG_NOTICE("Removed vrf netdev %s", vrfName.c_str()); + } + else + { + SWSS_LOG_ERROR("Unknown operation: %s", op.c_str()); + } + + it = consumer.m_toSync.erase(it); + } +} diff --git a/cfgmgr/vrfmgr.h b/cfgmgr/vrfmgr.h new file mode 100644 index 000000000000..127c05c85f34 --- /dev/null +++ b/cfgmgr/vrfmgr.h @@ -0,0 +1,34 @@ +#ifndef __VRFMGR__ +#define __VRFMGR__ + +#include +#include +#include +#include "dbconnector.h" +#include "producerstatetable.h" +#include "orch.h" + +using namespace std; + +namespace swss { + +class VrfMgr : public Orch +{ +public: + VrfMgr(DBConnector *cfgDb, DBConnector *appDb, DBConnector *stateDb, const vector &tableNames); + using Orch::doTask; + +private: + bool delLink(const string& vrfName); + bool setLink(const string& vrfName); + void recycleTable(uint32_t table); + uint32_t getFreeTable(void); + void doTask(Consumer &consumer); + + map m_vrfTableMap; + set m_freeTables; +}; + +} + +#endif diff --git a/cfgmgr/vrfmgrd.cpp b/cfgmgr/vrfmgrd.cpp new file mode 100644 index 000000000000..9d76d93402c6 --- /dev/null +++ b/cfgmgr/vrfmgrd.cpp @@ -0,0 +1,89 @@ +#include +#include +#include +#include "dbconnector.h" +#include "select.h" +#include "exec.h" +#include "schema.h" +#include "vrfmgr.h" +#include +#include + +using namespace std; +using namespace swss; + +/* select() function timeout retry time, in millisecond */ +#define SELECT_TIMEOUT 1000 + +/* + * Following global variables are defined here for the purpose of + * using existing Orch class which is to be refactored soon to + * eliminate the direct exposure of the global variables. + * + * Once Orch class refactoring is done, these global variables + * should be removed from here. + */ +int gBatchSize = 0; +bool gSwssRecord = false; +bool gLogRotate = false; +ofstream gRecordOfs; +string gRecordFile; +/* Global database mutex */ +mutex gDbMutex; + +int main(int argc, char **argv) +{ + Logger::linkToDbNative("vrfmgrd"); + SWSS_LOG_ENTER(); + + SWSS_LOG_NOTICE("--- Starting vrfmgrd ---"); + + try + { + vector cfg_vrf_tables = { + CFG_VRF_TABLE_NAME, + }; + + DBConnector cfgDb(CONFIG_DB, DBConnector::DEFAULT_UNIXSOCKET, 0); + DBConnector appDb(APPL_DB, DBConnector::DEFAULT_UNIXSOCKET, 0); + DBConnector stateDb(STATE_DB, DBConnector::DEFAULT_UNIXSOCKET, 0); + + VrfMgr vrfmgr(&cfgDb, &appDb, &stateDb, cfg_vrf_tables); + + // TODO: add tables in stateDB which interface depends on to monitor list + std::vector cfgOrchList = {&vrfmgr}; + + swss::Select s; + for (Orch *o : cfgOrchList) + { + s.addSelectables(o->getSelectables()); + } + + SWSS_LOG_NOTICE("starting main loop"); + 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) + { + vrfmgr.doTask(); + continue; + } + + auto *c = (Executor *)sel; + c->execute(); + } + } + catch(const std::exception &e) + { + SWSS_LOG_ERROR("Runtime error: %s", e.what()); + } + return -1; +}