Skip to content

Commit 671f248

Browse files
author
Shuotian Cheng
authored
[portmgrd]: Add portmgrd to monitor port MTU configurations (sonic-net#545)
In order to get rid of /etc/network/interfaces file and move all the configurations to the configuration database, MTU configurations are required to be put into the database and monitored by a specific daemon. This daemon portmgrd is to achieve this goal. Currently, this daemon will only listen to the port MTU configurations if existed in the database and then call the 'ip link' command to configure the kernel netdevs. It will also capture the admin status set in the configuration database and call the 'ip link' command to configure the kernel netdevs. The default MTUs, however, are set as the default value in the orchagent port.h file. The MTU value in the netlink message is anyway ignored. In the next stage, the change of the MTU will be supported so that the kernel host interface MTU will be reflected to the SAI port/router interface MTU. Signed-off-by: Shu0T1an ChenG <[email protected]>
1 parent 4eeecfd commit 671f248

File tree

7 files changed

+258
-17
lines changed

7 files changed

+258
-17
lines changed

cfgmgr/Makefile.am

+6-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
INCLUDES = -I $(top_srcdir) -I $(top_srcdir)/orchagent
22
CFLAGS_SAI = -I /usr/include/sai
33

4-
bin_PROGRAMS = vlanmgrd intfmgrd buffermgrd
4+
bin_PROGRAMS = vlanmgrd portmgrd intfmgrd buffermgrd
55

66
if DEBUG
77
DBGFLAGS = -ggdb -DDEBUG
@@ -14,6 +14,11 @@ vlanmgrd_CFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI)
1414
vlanmgrd_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI)
1515
vlanmgrd_LDADD = -lswsscommon
1616

17+
portmgrd_SOURCES = portmgrd.cpp portmgr.cpp $(top_srcdir)/orchagent/orch.cpp $(top_srcdir)/orchagent/request_parser.cpp shellcmd.h
18+
portmgrd_CFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI)
19+
portmgrd_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI)
20+
portmgrd_LDADD = -lswsscommon
21+
1722
intfmgrd_SOURCES = intfmgrd.cpp intfmgr.cpp $(top_srcdir)/orchagent/orch.cpp $(top_srcdir)/orchagent/request_parser.cpp shellcmd.h
1823
intfmgrd_CFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI)
1924
intfmgrd_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI)

cfgmgr/portmgr.cpp

+109
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
#include <string>
2+
#include "logger.h"
3+
#include "dbconnector.h"
4+
#include "producerstatetable.h"
5+
#include "tokenize.h"
6+
#include "ipprefix.h"
7+
#include "portmgr.h"
8+
#include "exec.h"
9+
#include "shellcmd.h"
10+
11+
using namespace std;
12+
using namespace swss;
13+
14+
PortMgr::PortMgr(DBConnector *cfgDb, DBConnector *appDb, DBConnector *stateDb, const vector<string> &tableNames) :
15+
Orch(cfgDb, tableNames),
16+
m_cfgPortTable(cfgDb, CFG_PORT_TABLE_NAME),
17+
m_cfgLagTable(cfgDb, CFG_LAG_TABLE_NAME),
18+
m_statePortTable(stateDb, STATE_PORT_TABLE_NAME),
19+
m_stateLagTable(stateDb, STATE_LAG_TABLE_NAME)
20+
{
21+
}
22+
23+
bool PortMgr::setPortMtu(const string &alias, const string &mtu)
24+
{
25+
stringstream cmd;
26+
string res;
27+
28+
cmd << IP_CMD << " link set dev " << alias << " mtu " << mtu;
29+
return exec(cmd.str(), res) == 0;
30+
}
31+
32+
bool PortMgr::setPortAdminStatus(const string &alias, const bool up)
33+
{
34+
stringstream cmd;
35+
string res;
36+
37+
cmd << IP_CMD << " link set dev " << alias << (up ? " up" : " down");
38+
return exec(cmd.str(), res) == 0;
39+
}
40+
41+
bool PortMgr::isPortStateOk(const string &table, const string &alias)
42+
{
43+
vector<FieldValueTuple> temp;
44+
45+
if (table == CFG_PORT_TABLE_NAME)
46+
{
47+
if (m_statePortTable.get(alias, temp))
48+
{
49+
SWSS_LOG_INFO("Port %s is ready", alias.c_str());
50+
return true;
51+
}
52+
}
53+
else if (table == CFG_LAG_TABLE_NAME)
54+
{
55+
if (m_stateLagTable.get(alias, temp))
56+
{
57+
SWSS_LOG_INFO("Lag %s is ready", alias.c_str());
58+
return true;
59+
}
60+
}
61+
62+
return false;
63+
}
64+
65+
void PortMgr::doTask(Consumer &consumer)
66+
{
67+
SWSS_LOG_ENTER();
68+
69+
auto table = consumer.getTableName();
70+
71+
auto it = consumer.m_toSync.begin();
72+
while (it != consumer.m_toSync.end())
73+
{
74+
KeyOpFieldsValuesTuple t = it->second;
75+
76+
string alias = kfvKey(t);
77+
string op = kfvOp(t);
78+
79+
if (op == SET_COMMAND)
80+
{
81+
if (!isPortStateOk(table, alias))
82+
{
83+
SWSS_LOG_INFO("Port %s is not ready, pending", alias.c_str());
84+
it++;
85+
continue;
86+
}
87+
88+
for (auto i : kfvFieldsValues(t))
89+
{
90+
if (fvField(i) == "mtu")
91+
{
92+
auto mtu = fvValue(i);
93+
setPortMtu(alias, mtu);
94+
SWSS_LOG_NOTICE("Configure %s MTU to %s",
95+
alias.c_str(), mtu.c_str());
96+
}
97+
else if (fvField(i) == "admin_status")
98+
{
99+
auto status = fvValue(i);
100+
setPortAdminStatus(alias, status == "up");
101+
SWSS_LOG_NOTICE("Configure %s %s",
102+
alias.c_str(), status.c_str());
103+
}
104+
}
105+
}
106+
107+
it = consumer.m_toSync.erase(it);
108+
}
109+
}

cfgmgr/portmgr.h

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
#ifndef __INTFMGR__
2+
#define __INTFMGR__
3+
4+
#include "dbconnector.h"
5+
#include "producerstatetable.h"
6+
#include "orch.h"
7+
8+
#include <map>
9+
#include <string>
10+
11+
namespace swss {
12+
13+
class PortMgr : public Orch
14+
{
15+
public:
16+
PortMgr(DBConnector *cfgDb, DBConnector *appDb, DBConnector *stateDb, const vector<string> &tableNames);
17+
using Orch::doTask;
18+
19+
private:
20+
Table m_cfgPortTable;
21+
Table m_cfgLagTable;
22+
Table m_statePortTable;
23+
Table m_stateLagTable;
24+
25+
void doTask(Consumer &consumer);
26+
bool setPortMtu(const string &alias, const string &mtu);
27+
bool setPortAdminStatus(const string &alias, const bool up);
28+
bool isPortStateOk(const string &table, const string &alias);
29+
};
30+
31+
}
32+
33+
#endif

cfgmgr/portmgrd.cpp

+89
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
#include <unistd.h>
2+
#include <vector>
3+
#include <mutex>
4+
#include "dbconnector.h"
5+
#include "select.h"
6+
#include "exec.h"
7+
#include "schema.h"
8+
#include "portmgr.h"
9+
#include <fstream>
10+
#include <iostream>
11+
12+
using namespace std;
13+
using namespace swss;
14+
15+
/* select() function timeout retry time, in millisecond */
16+
#define SELECT_TIMEOUT 1000
17+
18+
/*
19+
* Following global variables are defined here for the purpose of
20+
* using existing Orch class which is to be refactored soon to
21+
* eliminate the direct exposure of the global variables.
22+
*
23+
* Once Orch class refactoring is done, these global variables
24+
* should be removed from here.
25+
*/
26+
int gBatchSize = 0;
27+
bool gSwssRecord = false;
28+
bool gLogRotate = false;
29+
ofstream gRecordOfs;
30+
string gRecordFile;
31+
/* Global database mutex */
32+
mutex gDbMutex;
33+
34+
int main(int argc, char **argv)
35+
{
36+
Logger::linkToDbNative("portmgrd");
37+
SWSS_LOG_ENTER();
38+
39+
SWSS_LOG_NOTICE("--- Starting portmgrd ---");
40+
41+
try
42+
{
43+
vector<string> cfg_port_tables = {
44+
CFG_PORT_TABLE_NAME,
45+
CFG_LAG_TABLE_NAME,
46+
};
47+
48+
DBConnector cfgDb(CONFIG_DB, DBConnector::DEFAULT_UNIXSOCKET, 0);
49+
DBConnector appDb(APPL_DB, DBConnector::DEFAULT_UNIXSOCKET, 0);
50+
DBConnector stateDb(STATE_DB, DBConnector::DEFAULT_UNIXSOCKET, 0);
51+
52+
PortMgr portmgr(&cfgDb, &appDb, &stateDb, cfg_port_tables);
53+
54+
// TODO: add tables in stateDB which interface depends on to monitor list
55+
std::vector<Orch *> cfgOrchList = {&portmgr};
56+
57+
swss::Select s;
58+
for (Orch *o : cfgOrchList)
59+
{
60+
s.addSelectables(o->getSelectables());
61+
}
62+
63+
while (true)
64+
{
65+
Selectable *sel;
66+
int ret;
67+
68+
ret = s.select(&sel, SELECT_TIMEOUT);
69+
if (ret == Select::ERROR)
70+
{
71+
SWSS_LOG_NOTICE("Error: %s!", strerror(errno));
72+
continue;
73+
}
74+
if (ret == Select::TIMEOUT)
75+
{
76+
portmgr.doTask();
77+
continue;
78+
}
79+
80+
auto *c = (Executor *)sel;
81+
c->execute();
82+
}
83+
}
84+
catch(const std::exception &e)
85+
{
86+
SWSS_LOG_ERROR("Runtime error: %s", e.what());
87+
}
88+
return -1;
89+
}

portsyncd/linksync.cpp

-3
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,6 @@ void LinkSync::onMsg(int nlmsg_type, struct nl_object *obj)
110110
unsigned int flags = rtnl_link_get_flags(link);
111111
bool admin = flags & IFF_UP;
112112
bool oper = flags & IFF_LOWER_UP;
113-
unsigned int mtu = rtnl_link_get_mtu(link);
114113

115114
char addrStr[MAX_ADDR_SIZE+1] = {0};
116115
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)
155154

156155
vector<FieldValueTuple> fvVector;
157156
FieldValueTuple a("admin_status", admin ? "up" : "down");
158-
FieldValueTuple m("mtu", to_string(mtu));
159157
fvVector.push_back(a);
160-
fvVector.push_back(m);
161158

162159
/* front panel interfaces: Check if the port is in the PORT_TABLE
163160
* non-front panel interfaces such as eth0, lo which are not in the

portsyncd/portsyncd.cpp

-13
Original file line numberDiff line numberDiff line change
@@ -291,19 +291,6 @@ void handlePortConfig(ProducerStateTable &p, map<string, KeyOpFieldsValuesTuple>
291291
if (op == SET_COMMAND)
292292
{
293293
p.set(key, values);
294-
for (auto fv : values)
295-
{
296-
string field = fvField(fv);
297-
string value = fvValue(fv);
298-
299-
/* Update the mtu field on host interface */
300-
if (field == "mtu")
301-
{
302-
string cmd, res;
303-
cmd = "ip link set " + key + " mtu " + value;
304-
swss::exec(cmd, res);
305-
}
306-
}
307294
}
308295

309296
it = port_cfg_map.erase(it);

tests/test_port.py

+21
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,28 @@
11
from swsscommon import swsscommon
2+
23
import time
34
import os
45

6+
class TestPort(object):
7+
def test_PortMtu(self, dvs):
8+
pdb = swsscommon.DBConnector(0, dvs.redis_sock, 0)
9+
adb = swsscommon.DBConnector(1, dvs.redis_sock, 0)
10+
cdb = swsscommon.DBConnector(4, dvs.redis_sock, 0)
11+
12+
# set MTU to port
13+
tbl = swsscommon.Table(cdb, "PORT")
14+
fvs = swsscommon.FieldValuePairs([("MTU", "9100")])
15+
tbl.set("Ethernet8", fvs)
16+
time.sleep(1)
17+
18+
# check application database
19+
tbl = swsscommon.Table(pdb, "PORT_TABLE")
20+
(status, fvs) = tbl.get("Ethernet8")
21+
assert status == True
22+
for fv in fvs:
23+
if fv[0] == "mtu":
24+
assert fv[1] == "9100"
25+
526
def test_PortNotification(dvs):
627

728
dvs.runcmd("ifconfig Ethernet0 10.0.0.0/31 up") == 0

0 commit comments

Comments
 (0)