Skip to content

Commit 60a90d7

Browse files
andriymoroz-mlnxyxieca
authored andcommitted
Add Buffer Config Manager (#417)
* Add Buffer Config Manager Signed-off-by: Andriy Moroz <[email protected]> * Added comment Signed-off-by: Andriy Moroz <[email protected]> * Ignore port speed validation if not implemented Signed-off-by: Andriy Moroz <[email protected]> * Add speed and buffer set test Signed-off-by: Andriy Moroz <[email protected]> * Removed trailing newlines Signed-off-by: Andriy Moroz <[email protected]> * Revert "Removed trailing newlines" This reverts commit e485c35. * Revert "Add speed and buffer set test" This reverts commit 97206b1.
1 parent 2bd7aab commit 60a90d7

File tree

7 files changed

+417
-26
lines changed

7 files changed

+417
-26
lines changed

cfgmgr/Makefile.am

+7-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
4+
bin_PROGRAMS = vlanmgrd intfmgrd buffermgrd
55

66
if DEBUG
77
DBGFLAGS = -ggdb -DDEBUG
@@ -18,3 +18,9 @@ intfmgrd_SOURCES = intfmgrd.cpp intfmgr.cpp $(top_srcdir)/orchagent/orch.cpp $(t
1818
intfmgrd_CFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI)
1919
intfmgrd_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI)
2020
intfmgrd_LDADD = -lswsscommon
21+
22+
buffermgrd_SOURCES = buffermgrd.cpp buffermgr.cpp $(top_srcdir)/orchagent/orch.cpp $(top_srcdir)/orchagent/request_parser.cpp shellcmd.h
23+
buffermgrd_CFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI)
24+
buffermgrd_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI)
25+
buffermgrd_LDADD = -lswsscommon
26+

cfgmgr/buffermgr.cpp

+202
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,202 @@
1+
#include <fstream>
2+
#include <iostream>
3+
#include <string.h>
4+
#include "logger.h"
5+
#include "dbconnector.h"
6+
#include "producerstatetable.h"
7+
#include "tokenize.h"
8+
#include "ipprefix.h"
9+
#include "buffermgr.h"
10+
#include "exec.h"
11+
#include "shellcmd.h"
12+
13+
using namespace std;
14+
using namespace swss;
15+
16+
BufferMgr::BufferMgr(DBConnector *cfgDb, DBConnector *stateDb, string pg_lookup_file, const vector<string> &tableNames) :
17+
Orch(cfgDb, tableNames),
18+
m_statePortTable(stateDb, STATE_PORT_TABLE_NAME, CONFIGDB_TABLE_NAME_SEPARATOR),
19+
m_cfgPortTable(cfgDb, CFG_PORT_TABLE_NAME, CONFIGDB_TABLE_NAME_SEPARATOR),
20+
m_cfgCableLenTable(cfgDb, CFG_PORT_CABLE_LEN_TABLE_NAME, CONFIGDB_TABLE_NAME_SEPARATOR),
21+
m_cfgBufferProfileTable(cfgDb, CFG_BUFFER_PROFILE_TABLE_NAME, CONFIGDB_TABLE_NAME_SEPARATOR),
22+
m_cfgBufferPgTable(cfgDb, CFG_BUFFER_PG_TABLE_NAME, CONFIGDB_TABLE_NAME_SEPARATOR),
23+
m_cfgLosslessPgPoolTable(cfgDb, CFG_BUFFER_POOL_TABLE_NAME, CONFIGDB_TABLE_NAME_SEPARATOR)
24+
{
25+
readPgProfileLookupFile(pg_lookup_file);
26+
}
27+
28+
//# speed, cable, size, xon, xoff, threshold
29+
// 40000 5m 34816 18432 16384 1
30+
void BufferMgr::readPgProfileLookupFile(string file)
31+
{
32+
SWSS_LOG_NOTICE("Read lookup configuration file...");
33+
34+
ifstream infile(file);
35+
if (!infile.is_open())
36+
{
37+
return;
38+
}
39+
40+
string line;
41+
while (getline(infile, line))
42+
{
43+
if (line.empty() || (line.at(0) == '#'))
44+
{
45+
continue;
46+
}
47+
48+
istringstream iss(line);
49+
string speed, cable;
50+
51+
iss >> speed;
52+
iss >> cable;
53+
iss >> m_pgProfileLookup[speed][cable].size;
54+
iss >> m_pgProfileLookup[speed][cable].xon;
55+
iss >> m_pgProfileLookup[speed][cable].xoff;
56+
iss >> m_pgProfileLookup[speed][cable].threshold;
57+
58+
SWSS_LOG_NOTICE("PG profile for speed %s and cable %s is: size:%s, xon:%s xoff:%s th:%s",
59+
speed.c_str(), cable.c_str(),
60+
m_pgProfileLookup[speed][cable].size.c_str(),
61+
m_pgProfileLookup[speed][cable].xon.c_str(),
62+
m_pgProfileLookup[speed][cable].xoff.c_str(),
63+
m_pgProfileLookup[speed][cable].threshold.c_str()
64+
);
65+
}
66+
67+
infile.close();
68+
}
69+
70+
void BufferMgr::doCableTask(string port, string cable_length)
71+
{
72+
m_cableLenLookup[port] = cable_length;
73+
}
74+
75+
string BufferMgr::getPgPoolMode()
76+
{
77+
vector<FieldValueTuple> pool_properties;
78+
m_cfgLosslessPgPoolTable.get(INGRESS_LOSSLESS_PG_POOL_NAME, pool_properties);
79+
for (auto& prop : pool_properties)
80+
{
81+
if (fvField(prop) == "mode")
82+
return fvValue(prop);
83+
}
84+
return "";
85+
}
86+
87+
/*
88+
Create/update two tables: profile (in m_cfgBufferProfileTable) and port buffer (in m_cfgBufferPgTable):
89+
90+
"BUFFER_PROFILE": {
91+
"pg_lossless_100G_300m_profile": {
92+
"pool":"[BUFFER_POOL_TABLE:ingress_lossless_pool]",
93+
"xon":"18432",
94+
"xoff":"165888",
95+
"size":"184320",
96+
"dynamic_th":"1"
97+
}
98+
}
99+
"BUFFER_PG" :{
100+
Ethernet44|3-4": {
101+
"profile" : "[BUFFER_PROFILE:pg_lossless_100000_300m_profile]"
102+
}
103+
}
104+
*/
105+
void BufferMgr::doSpeedUpdateTask(string port, string speed)
106+
{
107+
vector<FieldValueTuple> fvVector;
108+
string cable;
109+
110+
if (m_cableLenLookup.count(port) == 0)
111+
{
112+
SWSS_LOG_ERROR("Unable to create/update PG profile for port %s. Cable length is not set", port.c_str());
113+
return;
114+
}
115+
116+
cable = m_cableLenLookup[port];
117+
118+
if (m_pgProfileLookup.count(speed) == 0 || m_pgProfileLookup[speed].count(cable) == 0)
119+
{
120+
SWSS_LOG_ERROR("Unable to create/update PG profile for port %s. No PG profile configured for speed %s and cable length %s",
121+
port.c_str(), speed.c_str(), cable.c_str());
122+
return;
123+
}
124+
125+
// Crete record in BUFFER_PROFILE table
126+
// key format is pg_lossless_<speed>_<cable>_profile
127+
string buffer_pg_key = port + CONFIGDB_TABLE_NAME_SEPARATOR + LOSSLESS_PGS;
128+
string buffer_profile_key = "pg_lossless_" + speed + "_" + cable + "_profile";
129+
130+
// check if profile already exists - if yes - skip creation
131+
m_cfgBufferProfileTable.get(buffer_profile_key, fvVector);
132+
if (fvVector.size() == 0)
133+
{
134+
SWSS_LOG_NOTICE("Creating new profile '%s'", buffer_profile_key.c_str());
135+
136+
string mode = getPgPoolMode();
137+
if (mode.empty())
138+
{
139+
// this should never happen if switch initialized properly
140+
SWSS_LOG_ERROR("PG lossless pool is not yet created");
141+
return;
142+
}
143+
144+
// profile threshold field name
145+
mode += "_th";
146+
string pg_pool_reference = string(CFG_BUFFER_POOL_TABLE_NAME) + CONFIGDB_TABLE_NAME_SEPARATOR + INGRESS_LOSSLESS_PG_POOL_NAME;
147+
fvVector.push_back(make_pair("pool", "[" + pg_pool_reference + "]"));
148+
fvVector.push_back(make_pair("xon", m_pgProfileLookup[speed][cable].xon));
149+
fvVector.push_back(make_pair("xoff", m_pgProfileLookup[speed][cable].xoff));
150+
fvVector.push_back(make_pair("size", m_pgProfileLookup[speed][cable].size));
151+
fvVector.push_back(make_pair(mode, m_pgProfileLookup[speed][cable].threshold));
152+
m_cfgBufferProfileTable.set(buffer_profile_key, fvVector);
153+
}
154+
else
155+
{
156+
SWSS_LOG_NOTICE("Reusing existing profile '%s'", buffer_profile_key.c_str());
157+
}
158+
159+
fvVector.clear();
160+
string profile_ref = string("[") + CFG_BUFFER_PROFILE_TABLE_NAME + CONFIGDB_TABLE_NAME_SEPARATOR + buffer_profile_key + "]";
161+
fvVector.push_back(make_pair("profile", profile_ref));
162+
m_cfgBufferPgTable.set(buffer_pg_key, fvVector);
163+
}
164+
165+
void BufferMgr::doTask(Consumer &consumer)
166+
{
167+
SWSS_LOG_ENTER();
168+
169+
string table_name = consumer.getTableName();
170+
171+
auto it = consumer.m_toSync.begin();
172+
while (it != consumer.m_toSync.end())
173+
{
174+
KeyOpFieldsValuesTuple t = it->second;
175+
176+
string keySeparator = CONFIGDB_KEY_SEPARATOR;
177+
vector<string> keys = tokenize(kfvKey(t), keySeparator[0]);
178+
string port(keys[0]);
179+
180+
string op = kfvOp(t);
181+
if (op == SET_COMMAND)
182+
{
183+
for (auto i : kfvFieldsValues(t))
184+
{
185+
if (table_name == CFG_PORT_CABLE_LEN_TABLE_NAME)
186+
{
187+
// receive and cache cable length table
188+
doCableTask(fvField(i), fvValue(i));
189+
}
190+
// In case of PORT table update, Buffer Manager is interested in speed update only
191+
if (table_name == CFG_PORT_TABLE_NAME && fvField(i) == "speed")
192+
{
193+
// create/update profile for port
194+
doSpeedUpdateTask(port, fvValue(i));
195+
}
196+
}
197+
}
198+
199+
it = consumer.m_toSync.erase(it);
200+
continue;
201+
}
202+
}

cfgmgr/buffermgr.h

+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
#ifndef __BUFFMGR__
2+
#define __BUFFMGR__
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+
#define INGRESS_LOSSLESS_PG_POOL_NAME "ingress_lossless_pool"
14+
#define LOSSLESS_PGS "3-4"
15+
16+
typedef struct{
17+
string size;
18+
string xon;
19+
string xoff;
20+
string threshold;
21+
} pg_profile_t;
22+
23+
typedef map<string, pg_profile_t> speed_map_t;
24+
typedef map<string, speed_map_t> pg_profile_lookup_t;
25+
26+
typedef map<string, string> port_cable_length_t;
27+
28+
class BufferMgr : public Orch
29+
{
30+
public:
31+
BufferMgr(DBConnector *cfgDb, DBConnector *stateDb, string pg_lookup_file, const vector<string> &tableNames);
32+
using Orch::doTask;
33+
34+
private:
35+
Table m_statePortTable;
36+
Table m_cfgPortTable;
37+
Table m_cfgCableLenTable;
38+
Table m_cfgBufferProfileTable;
39+
Table m_cfgBufferPgTable;
40+
Table m_cfgLosslessPgPoolTable;
41+
42+
pg_profile_lookup_t m_pgProfileLookup;
43+
port_cable_length_t m_cableLenLookup;
44+
std::string getPgPoolMode();
45+
void readPgProfileLookupFile(std::string);
46+
void doCableTask(string port, string cable_length);
47+
void doSpeedUpdateTask(string port, string speed);
48+
49+
void doTask(Consumer &consumer);
50+
};
51+
52+
}
53+
54+
#endif /* __BUFFMGR__ */

cfgmgr/buffermgrd.cpp

+122
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
#include <unistd.h>
2+
#include <getopt.h>
3+
#include <vector>
4+
#include <mutex>
5+
#include "dbconnector.h"
6+
#include "select.h"
7+
#include "exec.h"
8+
#include "schema.h"
9+
#include "buffermgr.h"
10+
#include <fstream>
11+
#include <iostream>
12+
13+
using namespace std;
14+
using namespace swss;
15+
16+
/* select() function timeout retry time, in millisecond */
17+
#define SELECT_TIMEOUT 1000
18+
19+
/*
20+
* Following global variables are defined here for the purpose of
21+
* using existing Orch class which is to be refactored soon to
22+
* eliminate the direct exposure of the global variables.
23+
*
24+
* Once Orch class refactoring is done, these global variables
25+
* should be removed from here.
26+
*/
27+
int gBatchSize = 0;
28+
bool gSwssRecord = false;
29+
bool gLogRotate = false;
30+
ofstream gRecordOfs;
31+
string gRecordFile;
32+
/* Global database mutex */
33+
mutex gDbMutex;
34+
35+
void usage()
36+
{
37+
cout << "Usage: buffermgrd -l pg_lookup.ini" << endl;
38+
cout << " -l pg_lookup.ini: PG profile look up table file (mandatory)" << endl;
39+
cout << " format: csv" << endl;
40+
cout << " values: 'speed, cable, size, xon, xoff, dynamic_threshold'" << endl;
41+
}
42+
43+
int main(int argc, char **argv)
44+
{
45+
int opt;
46+
string pg_lookup_file = "";
47+
Logger::linkToDbNative("buffermgrd");
48+
SWSS_LOG_ENTER();
49+
50+
SWSS_LOG_NOTICE("--- Starting buffermgrd ---");
51+
52+
while ((opt = getopt(argc, argv, "l:h")) != -1 )
53+
{
54+
switch (opt)
55+
{
56+
case 'l':
57+
pg_lookup_file = optarg;
58+
break;
59+
case 'h':
60+
usage();
61+
return 1;
62+
default: /* '?' */
63+
usage();
64+
return EXIT_FAILURE;
65+
}
66+
}
67+
68+
if (pg_lookup_file.empty())
69+
{
70+
usage();
71+
return EXIT_FAILURE;
72+
}
73+
74+
try
75+
{
76+
vector<string> cfg_buffer_tables = {
77+
CFG_PORT_TABLE_NAME,
78+
CFG_PORT_CABLE_LEN_TABLE_NAME,
79+
};
80+
81+
DBConnector cfgDb(CONFIG_DB, DBConnector::DEFAULT_UNIXSOCKET, 0);
82+
DBConnector stateDb(STATE_DB, DBConnector::DEFAULT_UNIXSOCKET, 0);
83+
84+
BufferMgr buffmgr(&cfgDb, &stateDb, pg_lookup_file, cfg_buffer_tables);
85+
86+
// TODO: add tables in stateDB which interface depends on to monitor list
87+
std::vector<Orch *> cfgOrchList = {&buffmgr};
88+
89+
swss::Select s;
90+
for (Orch *o : cfgOrchList)
91+
{
92+
s.addSelectables(o->getSelectables());
93+
}
94+
95+
SWSS_LOG_NOTICE("starting main loop");
96+
while (true)
97+
{
98+
Selectable *sel;
99+
int fd, ret;
100+
101+
ret = s.select(&sel, &fd, SELECT_TIMEOUT);
102+
if (ret == Select::ERROR)
103+
{
104+
SWSS_LOG_NOTICE("Error: %s!", strerror(errno));
105+
continue;
106+
}
107+
if (ret == Select::TIMEOUT)
108+
{
109+
buffmgr.doTask();
110+
continue;
111+
}
112+
113+
auto *c = (Executor *)sel;
114+
c->execute();
115+
}
116+
}
117+
catch(const std::exception &e)
118+
{
119+
SWSS_LOG_ERROR("Runtime error: %s", e.what());
120+
}
121+
return -1;
122+
}

0 commit comments

Comments
 (0)