diff --git a/cfgmgr/Makefile.am b/cfgmgr/Makefile.am index 258d7659be..60c891491d 100644 --- a/cfgmgr/Makefile.am +++ b/cfgmgr/Makefile.am @@ -1,7 +1,7 @@ INCLUDES = -I $(top_srcdir) -I $(top_srcdir)/orchagent CFLAGS_SAI = -I /usr/include/sai -bin_PROGRAMS = vlanmgrd intfmgrd buffermgrd +bin_PROGRAMS = vlanmgrd portmgrd intfmgrd buffermgrd if DEBUG DBGFLAGS = -ggdb -DDEBUG @@ -14,6 +14,11 @@ vlanmgrd_CFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI) vlanmgrd_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI) vlanmgrd_LDADD = -lswsscommon +portmgrd_SOURCES = portmgrd.cpp portmgr.cpp $(top_srcdir)/orchagent/orch.cpp $(top_srcdir)/orchagent/request_parser.cpp shellcmd.h +portmgrd_CFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI) +portmgrd_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI) +portmgrd_LDADD = -lswsscommon + intfmgrd_SOURCES = intfmgrd.cpp intfmgr.cpp $(top_srcdir)/orchagent/orch.cpp $(top_srcdir)/orchagent/request_parser.cpp shellcmd.h intfmgrd_CFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI) intfmgrd_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI) diff --git a/cfgmgr/portmgr.cpp b/cfgmgr/portmgr.cpp new file mode 100644 index 0000000000..1dc74b9367 --- /dev/null +++ b/cfgmgr/portmgr.cpp @@ -0,0 +1,109 @@ +#include +#include "logger.h" +#include "dbconnector.h" +#include "producerstatetable.h" +#include "tokenize.h" +#include "ipprefix.h" +#include "portmgr.h" +#include "exec.h" +#include "shellcmd.h" + +using namespace std; +using namespace swss; + +PortMgr::PortMgr(DBConnector *cfgDb, DBConnector *appDb, DBConnector *stateDb, const vector &tableNames) : + Orch(cfgDb, tableNames), + m_cfgPortTable(cfgDb, CFG_PORT_TABLE_NAME), + m_cfgLagTable(cfgDb, CFG_LAG_TABLE_NAME), + m_statePortTable(stateDb, STATE_PORT_TABLE_NAME), + m_stateLagTable(stateDb, STATE_LAG_TABLE_NAME) +{ +} + +bool PortMgr::setPortMtu(const string &alias, const string &mtu) +{ + stringstream cmd; + string res; + + cmd << IP_CMD << " link set dev " << alias << " mtu " << mtu; + return exec(cmd.str(), res) == 0; +} + +bool PortMgr::setPortAdminStatus(const string &alias, const bool up) +{ + stringstream cmd; + string res; + + cmd << IP_CMD << " link set dev " << alias << (up ? " up" : " down"); + return exec(cmd.str(), res) == 0; +} + +bool PortMgr::isPortStateOk(const string &table, const string &alias) +{ + vector temp; + + if (table == CFG_PORT_TABLE_NAME) + { + if (m_statePortTable.get(alias, temp)) + { + SWSS_LOG_INFO("Port %s is ready", alias.c_str()); + return true; + } + } + else if (table == CFG_LAG_TABLE_NAME) + { + if (m_stateLagTable.get(alias, temp)) + { + SWSS_LOG_INFO("Lag %s is ready", alias.c_str()); + return true; + } + } + + return false; +} + +void PortMgr::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 alias = kfvKey(t); + string op = kfvOp(t); + + if (op == SET_COMMAND) + { + if (!isPortStateOk(table, alias)) + { + SWSS_LOG_INFO("Port %s is not ready, pending", alias.c_str()); + it++; + continue; + } + + for (auto i : kfvFieldsValues(t)) + { + if (fvField(i) == "mtu") + { + auto mtu = fvValue(i); + setPortMtu(alias, mtu); + SWSS_LOG_NOTICE("Configure %s MTU to %s", + alias.c_str(), mtu.c_str()); + } + else if (fvField(i) == "admin_status") + { + auto status = fvValue(i); + setPortAdminStatus(alias, status == "up"); + SWSS_LOG_NOTICE("Configure %s %s", + alias.c_str(), status.c_str()); + } + } + } + + it = consumer.m_toSync.erase(it); + } +} diff --git a/cfgmgr/portmgr.h b/cfgmgr/portmgr.h new file mode 100644 index 0000000000..341f95c588 --- /dev/null +++ b/cfgmgr/portmgr.h @@ -0,0 +1,33 @@ +#ifndef __INTFMGR__ +#define __INTFMGR__ + +#include "dbconnector.h" +#include "producerstatetable.h" +#include "orch.h" + +#include +#include + +namespace swss { + +class PortMgr : public Orch +{ +public: + PortMgr(DBConnector *cfgDb, DBConnector *appDb, DBConnector *stateDb, const vector &tableNames); + using Orch::doTask; + +private: + Table m_cfgPortTable; + Table m_cfgLagTable; + Table m_statePortTable; + Table m_stateLagTable; + + void doTask(Consumer &consumer); + bool setPortMtu(const string &alias, const string &mtu); + bool setPortAdminStatus(const string &alias, const bool up); + bool isPortStateOk(const string &table, const string &alias); +}; + +} + +#endif diff --git a/cfgmgr/portmgrd.cpp b/cfgmgr/portmgrd.cpp new file mode 100644 index 0000000000..5855c75c3f --- /dev/null +++ b/cfgmgr/portmgrd.cpp @@ -0,0 +1,89 @@ +#include +#include +#include +#include "dbconnector.h" +#include "select.h" +#include "exec.h" +#include "schema.h" +#include "portmgr.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("portmgrd"); + SWSS_LOG_ENTER(); + + SWSS_LOG_NOTICE("--- Starting portmgrd ---"); + + try + { + vector cfg_port_tables = { + CFG_PORT_TABLE_NAME, + CFG_LAG_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); + + PortMgr portmgr(&cfgDb, &appDb, &stateDb, cfg_port_tables); + + // TODO: add tables in stateDB which interface depends on to monitor list + std::vector cfgOrchList = {&portmgr}; + + 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) + { + portmgr.doTask(); + continue; + } + + auto *c = (Executor *)sel; + c->execute(); + } + } + catch(const std::exception &e) + { + SWSS_LOG_ERROR("Runtime error: %s", e.what()); + } + return -1; +} diff --git a/portsyncd/linksync.cpp b/portsyncd/linksync.cpp index fa64b68711..58ba56dc3c 100644 --- a/portsyncd/linksync.cpp +++ b/portsyncd/linksync.cpp @@ -110,7 +110,6 @@ void LinkSync::onMsg(int nlmsg_type, struct nl_object *obj) unsigned int flags = rtnl_link_get_flags(link); bool admin = flags & IFF_UP; bool oper = flags & IFF_LOWER_UP; - unsigned int mtu = rtnl_link_get_mtu(link); char addrStr[MAX_ADDR_SIZE+1] = {0}; nl_addr2str(rtnl_link_get_addr(link), addrStr, MAX_ADDR_SIZE); @@ -155,9 +154,7 @@ void LinkSync::onMsg(int nlmsg_type, struct nl_object *obj) vector fvVector; FieldValueTuple a("admin_status", admin ? "up" : "down"); - FieldValueTuple m("mtu", to_string(mtu)); fvVector.push_back(a); - fvVector.push_back(m); /* front panel interfaces: Check if the port is in the PORT_TABLE * non-front panel interfaces such as eth0, lo which are not in the diff --git a/portsyncd/portsyncd.cpp b/portsyncd/portsyncd.cpp index c49ba3da68..3d5d99b40a 100644 --- a/portsyncd/portsyncd.cpp +++ b/portsyncd/portsyncd.cpp @@ -291,19 +291,6 @@ void handlePortConfig(ProducerStateTable &p, map if (op == SET_COMMAND) { p.set(key, values); - for (auto fv : values) - { - string field = fvField(fv); - string value = fvValue(fv); - - /* Update the mtu field on host interface */ - if (field == "mtu") - { - string cmd, res; - cmd = "ip link set " + key + " mtu " + value; - swss::exec(cmd, res); - } - } } it = port_cfg_map.erase(it); diff --git a/tests/test_port.py b/tests/test_port.py index 929fe8c589..ce841800c3 100644 --- a/tests/test_port.py +++ b/tests/test_port.py @@ -1,7 +1,28 @@ from swsscommon import swsscommon + import time import os +class TestPort(object): + def test_PortMtu(self, dvs): + pdb = swsscommon.DBConnector(0, dvs.redis_sock, 0) + adb = swsscommon.DBConnector(1, dvs.redis_sock, 0) + cdb = swsscommon.DBConnector(4, dvs.redis_sock, 0) + + # set MTU to port + tbl = swsscommon.Table(cdb, "PORT") + fvs = swsscommon.FieldValuePairs([("MTU", "9100")]) + tbl.set("Ethernet8", fvs) + time.sleep(1) + + # check application database + tbl = swsscommon.Table(pdb, "PORT_TABLE") + (status, fvs) = tbl.get("Ethernet8") + assert status == True + for fv in fvs: + if fv[0] == "mtu": + assert fv[1] == "9100" + def test_PortNotification(dvs): dvs.runcmd("ifconfig Ethernet0 10.0.0.0/31 up") == 0