-
Notifications
You must be signed in to change notification settings - Fork 537
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[configdb]: configDB enforcer for interface (#357)
* configDB enforcer for interface Support VLAN interface only for now Signed-off-by: Jipan Yang <[email protected]> * Use OrchBase for configDB intf configuration enforcer Signed-off-by: Jipan Yang <[email protected]> * Rename intfconf to intfmgr Signed-off-by: Jipan Yang <[email protected]> * Use shell full path command macros Signed-off-by: Jipan Yang <[email protected]> * Optimize shell command execution error handling Signed-off-by: Jipan Yang <[email protected]> * Use Orch class for intfmgrd orchestration Signed-off-by: Jipan Yang <[email protected]>
- Loading branch information
Showing
5 changed files
with
259 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,126 @@ | ||
#include <string.h> | ||
#include "logger.h" | ||
#include "dbconnector.h" | ||
#include "producerstatetable.h" | ||
#include "tokenize.h" | ||
#include "ipprefix.h" | ||
#include "intfmgr.h" | ||
#include "exec.h" | ||
#include "shellcmd.h" | ||
|
||
using namespace std; | ||
using namespace swss; | ||
|
||
#define VLAN_PREFIX "Vlan" | ||
#define LAG_PREFIX "PortChannel" | ||
|
||
IntfMgr::IntfMgr(DBConnector *cfgDb, DBConnector *appDb, DBConnector *stateDb, const vector<string> &tableNames) : | ||
Orch(cfgDb, tableNames), | ||
m_cfgIntfTable(cfgDb, CFG_INTF_TABLE_NAME, CONFIGDB_TABLE_NAME_SEPARATOR), | ||
m_cfgVlanIntfTable(cfgDb, CFG_VLAN_INTF_TABLE_NAME, CONFIGDB_TABLE_NAME_SEPARATOR), | ||
m_statePortTable(stateDb, STATE_PORT_TABLE_NAME, CONFIGDB_TABLE_NAME_SEPARATOR), | ||
m_stateLagTable(stateDb, STATE_LAG_TABLE_NAME, CONFIGDB_TABLE_NAME_SEPARATOR), | ||
m_stateVlanTable(stateDb, STATE_VLAN_TABLE_NAME, CONFIGDB_TABLE_NAME_SEPARATOR), | ||
m_appIntfTableProducer(appDb, APP_INTF_TABLE_NAME) | ||
{ | ||
} | ||
|
||
bool IntfMgr::setIntfIp(const string &alias, const string &opCmd, const string &ipPrefixStr) | ||
{ | ||
stringstream cmd; | ||
string res; | ||
|
||
cmd << IP_CMD << " address " << opCmd << " " << ipPrefixStr << " dev " << alias;; | ||
int ret = swss::exec(cmd.str(), res); | ||
return (ret == 0); | ||
} | ||
|
||
bool IntfMgr::isIntfStateOk(const string &alias) | ||
{ | ||
vector<FieldValueTuple> temp; | ||
|
||
if (!alias.compare(0, strlen(VLAN_PREFIX), VLAN_PREFIX)) | ||
{ | ||
if (m_stateVlanTable.get(alias, temp)) | ||
{ | ||
SWSS_LOG_DEBUG("Vlan %s is ready", alias.c_str()); | ||
return true; | ||
} | ||
} | ||
else if (!alias.compare(0, strlen(LAG_PREFIX), LAG_PREFIX)) | ||
{ | ||
if (m_stateLagTable.get(alias, temp)) | ||
{ | ||
SWSS_LOG_DEBUG("Lag %s is ready", alias.c_str()); | ||
return true; | ||
} | ||
} | ||
else if (m_statePortTable.get(alias, temp)) | ||
{ | ||
SWSS_LOG_DEBUG("Port %s is ready", alias.c_str()); | ||
return true; | ||
} | ||
|
||
return false; | ||
} | ||
void IntfMgr::doTask(Consumer &consumer) | ||
{ | ||
SWSS_LOG_ENTER(); | ||
|
||
auto it = consumer.m_toSync.begin(); | ||
while (it != consumer.m_toSync.end()) | ||
{ | ||
KeyOpFieldsValuesTuple t = it->second; | ||
|
||
string keySeparator = CONFIGDB_KEY_SEPARATOR; | ||
vector<string> keys = tokenize(kfvKey(t), keySeparator[0]); | ||
string alias(keys[0]); | ||
|
||
if (alias.compare(0, strlen(VLAN_PREFIX), VLAN_PREFIX)) | ||
{ | ||
/* handle IP over vlan Only for now, skip the rest */ | ||
it = consumer.m_toSync.erase(it); | ||
continue; | ||
} | ||
|
||
size_t pos = kfvKey(t).find(CONFIGDB_KEY_SEPARATOR); | ||
if (pos == string::npos) | ||
{ | ||
SWSS_LOG_DEBUG("Invalid key %s", kfvKey(t).c_str()); | ||
it = consumer.m_toSync.erase(it); | ||
continue; | ||
} | ||
IpPrefix ip_prefix(kfvKey(t).substr(pos+1)); | ||
|
||
SWSS_LOG_DEBUG("intfs doTask: %s", (dumpTuple(consumer, t)).c_str()); | ||
|
||
string op = kfvOp(t); | ||
if (op == SET_COMMAND) | ||
{ | ||
/* | ||
* Don't proceed if port/lag/VLAN is not ready yet. | ||
* The pending task will be checked periodially and retried. | ||
* TODO: Subscribe to stateDB for port/lag/VLAN state and retry | ||
* pending tasks immediately upon state change. | ||
*/ | ||
if (!isIntfStateOk(alias)) | ||
{ | ||
SWSS_LOG_DEBUG("Interface is not ready, skipping %s", kfvKey(t).c_str()); | ||
it++; | ||
continue; | ||
} | ||
string opCmd("add"); | ||
string ipPrefixStr = ip_prefix.to_string(); | ||
setIntfIp(alias, opCmd, ipPrefixStr); | ||
} | ||
else if (op == DEL_COMMAND) | ||
{ | ||
string opCmd("del"); | ||
string ipPrefixStr = ip_prefix.to_string(); | ||
setIntfIp(alias, opCmd, ipPrefixStr); | ||
} | ||
|
||
it = consumer.m_toSync.erase(it); | ||
continue; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
#ifndef __INTFMGR__ | ||
#define __INTFMGR__ | ||
|
||
#include "dbconnector.h" | ||
#include "producerstatetable.h" | ||
#include "orch.h" | ||
|
||
#include <map> | ||
#include <string> | ||
|
||
namespace swss { | ||
|
||
class IntfMgr : public Orch | ||
{ | ||
public: | ||
IntfMgr(DBConnector *cfgDb, DBConnector *appDb, DBConnector *stateDb, const vector<string> &tableNames); | ||
|
||
private: | ||
ProducerStateTable m_appIntfTableProducer; | ||
Table m_cfgIntfTable, m_cfgVlanIntfTable; | ||
Table m_statePortTable, m_stateLagTable, m_stateVlanTable; | ||
|
||
bool setIntfIp(const string &alias, const string &opCmd, const string &ipPrefixStr); | ||
void doTask(Consumer &consumer); | ||
bool isIntfStateOk(const string &alias); | ||
}; | ||
|
||
} | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
#include <unistd.h> | ||
#include <vector> | ||
#include <mutex> | ||
#include "dbconnector.h" | ||
#include "select.h" | ||
#include "exec.h" | ||
#include "schema.h" | ||
#include "intfmgr.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("intfmgrd"); | ||
SWSS_LOG_ENTER(); | ||
|
||
SWSS_LOG_NOTICE("--- Starting intfmgrd ---"); | ||
|
||
try | ||
{ | ||
vector<string> cfg_intf_tables = { | ||
CFG_INTF_TABLE_NAME, | ||
CFG_LAG_INTF_TABLE_NAME, | ||
CFG_VLAN_INTF_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); | ||
|
||
IntfMgr intfmgr(&cfgDb, &appDb, &stateDb, cfg_intf_tables); | ||
|
||
// TODO: add tables in stateDB which interface depends on to monitor list | ||
std::vector<Orch *> cfgOrchList = {&intfmgr}; | ||
|
||
swss::Select s; | ||
for (Orch *o : cfgOrchList) | ||
{ | ||
s.addSelectables(o->getSelectables()); | ||
} | ||
|
||
SWSS_LOG_NOTICE("starting main loop"); | ||
while (true) | ||
{ | ||
Selectable *sel; | ||
int fd, ret; | ||
|
||
ret = s.select(&sel, &fd, SELECT_TIMEOUT); | ||
if (ret == Select::ERROR) | ||
{ | ||
SWSS_LOG_NOTICE("Error: %s!", strerror(errno)); | ||
continue; | ||
} | ||
if (ret == Select::TIMEOUT) | ||
{ | ||
((Orch *)&intfmgr)->doTask(); | ||
continue; | ||
} | ||
|
||
for (Orch *o : cfgOrchList) | ||
{ | ||
TableConsumable *c = (TableConsumable *)sel; | ||
if (o->hasSelectable(c)) | ||
{ | ||
o->execute(c->getTableName()); | ||
} | ||
} | ||
} | ||
} | ||
catch(const std::exception &e) | ||
{ | ||
SWSS_LOG_ERROR("Runtime error: %s", e.what()); | ||
} | ||
return -1; | ||
} |