Skip to content

[cfgmgr]: Add vrfmgrd #621

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Sep 19, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ intfsyncd/intfsyncd
cfgmgr/intfmgrd
cfgmgr/vlanmgrd
cfgmgr/buffermanager
cfgmgr/vrfmgrd
neighsyncd/neighsyncd
portsyncd/portsyncd
orchagent/orchagent
Expand Down
6 changes: 5 additions & 1 deletion cfgmgr/Makefile.am
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since every daemon here is taking "$(top_srcdir)/orchagent/orch.cpp $(top_srcdir)/orchagent/request_parser.cpp shellcmd.h", would it make sense to have a macro for them like

CFGMGR_COMMON_SOURCES = $(top_srcdir)/orchagent/orch.cpp $(top_srcdir)/orchagent/request_parser.cpp shellcmd.h

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe, but I don't like mixing that kind of refactoring with new features in a single PR

vrfmgrd_CFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI)
vrfmgrd_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI)
vrfmgrd_LDADD = -lswsscommon
175 changes: 175 additions & 0 deletions cfgmgr/vrfmgr.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
#include <string.h>
#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<string> &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<uint32_t>(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;
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we check the vrfTableMap, if it is there means the vrf has been created, then we can just return true. Instead of creating a new one.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

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);
}
}
34 changes: 34 additions & 0 deletions cfgmgr/vrfmgr.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#ifndef __VRFMGR__
#define __VRFMGR__

#include <string>
#include <map>
#include <set>
#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<string> &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<string, uint32_t> m_vrfTableMap;
set<uint32_t> m_freeTables;
};

}

#endif
89 changes: 89 additions & 0 deletions cfgmgr/vrfmgrd.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
#include <unistd.h>
#include <vector>
#include <mutex>
#include "dbconnector.h"
#include "select.h"
#include "exec.h"
#include "schema.h"
#include "vrfmgr.h"
#include <fstream>
#include <iostream>

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<string> 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<Orch *> 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;
}