Skip to content

Commit

Permalink
Sub port interface implementation (#969)
Browse files Browse the repository at this point in the history
IntfMgrd:
Listen to CONFIG_DB VLAN_SUB_INTERFACE table.
Process host sub port interface: create, set (admin_status), and remove using ip link and ip address system call, and update the STATE_DB
Relay the VLAN_SUB_INTERFACE table operation and field-value content to APPL_DB INTF_TABLE.

IntfOrch:
Listen to APPL_DB INTF_TABLE.
Process sub port interface on physical port: create (a Port object for sub port interface), set (admin_status), and remove.

PortsOrch:
Add member function to create a Port object for sub port interface

vs unit test:
sub port interface creation
sub port interface add IP addresses
sub port interface admin status change
sub port interface remove IP addresses
sub port interface removal

Signed-off-by: Wenda Ni <wenni@microsoft.com>
  • Loading branch information
wendani authored and lguohan committed Nov 8, 2019
1 parent c57fc34 commit 56d66a1
Show file tree
Hide file tree
Showing 13 changed files with 908 additions and 27 deletions.
256 changes: 247 additions & 9 deletions cfgmgr/intfmgr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,13 @@ using namespace swss;
#define LAG_PREFIX "PortChannel"
#define LOOPBACK_PREFIX "Loopback"
#define VNET_PREFIX "Vnet"
#define MTU_INHERITANCE "0"
#define VRF_PREFIX "Vrf"

#define LOOPBACK_DEFAULT_MTU_STR "65536"

IntfMgr::IntfMgr(DBConnector *cfgDb, DBConnector *appDb, DBConnector *stateDb, const vector<string> &tableNames) :
Orch(cfgDb, tableNames),
m_cfgIntfTable(cfgDb, CFG_INTF_TABLE_NAME),
m_cfgVlanIntfTable(cfgDb, CFG_VLAN_INTF_TABLE_NAME),
m_statePortTable(stateDb, STATE_PORT_TABLE_NAME),
m_stateLagTable(stateDb, STATE_LAG_TABLE_NAME),
m_stateVlanTable(stateDb, STATE_VLAN_TABLE_NAME),
Expand Down Expand Up @@ -167,6 +166,157 @@ bool IntfMgr::isIntfChangeVrf(const string &alias, const string &vrfName)
return false;
}

void IntfMgr::addHostSubIntf(const string&intf, const string &subIntf, const string &vlan)
{
// TODO: remove when validation check at mgmt is in place
for (const auto &c : intf)
{
if (!isalnum(c))
{
SWSS_LOG_ERROR("Invalid parent port name %s for host sub interface %s", intf.c_str(), subIntf.c_str());
return;
}
}
for (const auto &c : vlan)
{
if (!isdigit(c))
{
SWSS_LOG_ERROR("Invalid vlan id %s for host sub interface %s", vlan.c_str(), subIntf.c_str());
return;
}
}

stringstream cmd;
string res;

cmd << IP_CMD << " link add link " << intf << " name " << subIntf << " type vlan id " << vlan;
EXEC_WITH_ERROR_THROW(cmd.str(), res);
}

void IntfMgr::setHostSubIntfMtu(const string &subIntf, const string &mtu)
{
// TODO: remove when validation check at mgmt is in place
size_t found = subIntf.find(VLAN_SUB_INTERFACE_SEPARATOR);
if (found == string::npos)
{
SWSS_LOG_ERROR("Invalid host sub interface name: %s", subIntf.c_str());
return;
}
size_t i = 0;
for (const auto &c : subIntf)
{
if (i < found && !isalnum(c))
{
SWSS_LOG_ERROR("Invalid host sub interface name: %s", subIntf.c_str());
return;
}
else if (i > found && !isdigit(c))
{
SWSS_LOG_ERROR("Invalid host sub interface name: %s", subIntf.c_str());
return;
}
i++;
}

stringstream cmd;
string res;

cmd << IP_CMD << " link set " << subIntf << " mtu " << mtu;
EXEC_WITH_ERROR_THROW(cmd.str(), res);
}

void IntfMgr::setHostSubIntfAdminStatus(const string &subIntf, const string &adminStatus)
{
// TODO: remove when validation check at mgmt is in place
size_t found = subIntf.find(VLAN_SUB_INTERFACE_SEPARATOR);
if (found == string::npos)
{
SWSS_LOG_ERROR("Invalid host sub interface name: %s", subIntf.c_str());
return;
}
size_t i = 0;
for (const auto &c : subIntf)
{
if (i < found && !isalnum(c))
{
SWSS_LOG_ERROR("Invalid host sub interface name: %s", subIntf.c_str());
return;
}
else if (i > found && !isdigit(c))
{
SWSS_LOG_ERROR("Invalid host sub interface name: %s", subIntf.c_str());
return;
}
i++;
}

stringstream cmd;
string res;

cmd << IP_CMD << " link set " << subIntf << " " << adminStatus;
EXEC_WITH_ERROR_THROW(cmd.str(), res);
}

void IntfMgr::removeHostSubIntf(const string &subIntf)
{
// TODO: remove when validation check at mgmt is in place
size_t found = subIntf.find(VLAN_SUB_INTERFACE_SEPARATOR);
if (found == string::npos)
{
SWSS_LOG_ERROR("Invalid host sub interface name: %s", subIntf.c_str());
return;
}
size_t i = 0;
for (const auto &c : subIntf)
{
if (i < found && !isalnum(c))
{
SWSS_LOG_ERROR("Invalid host sub interface name: %s", subIntf.c_str());
return;
}
else if (i > found && !isdigit(c))
{
SWSS_LOG_ERROR("Invalid host sub interface name: %s", subIntf.c_str());
return;
}
i++;
}

stringstream cmd;
string res;

cmd << IP_CMD << " link del " << subIntf;
EXEC_WITH_ERROR_THROW(cmd.str(), res);
}

void IntfMgr::setSubIntfStateOk(const string &alias)
{
vector<FieldValueTuple> fvTuples = {{"state", "ok"}};

if (!alias.compare(0, strlen(LAG_PREFIX), LAG_PREFIX))
{
m_stateLagTable.set(alias, fvTuples);
}
else
{
// EthernetX using PORT_TABLE
m_statePortTable.set(alias, fvTuples);
}
}

void IntfMgr::removeSubIntfState(const string &alias)
{
if (!alias.compare(0, strlen(LAG_PREFIX), LAG_PREFIX))
{
m_stateLagTable.del(alias);
}
else
{
// EthernetX using PORT_TABLE
m_statePortTable.del(alias);
}
}

bool IntfMgr::isIntfStateOk(const string &alias)
{
vector<FieldValueTuple> temp;
Expand Down Expand Up @@ -217,23 +367,43 @@ bool IntfMgr::isIntfStateOk(const string &alias)
}

bool IntfMgr::doIntfGeneralTask(const vector<string>& keys,
const vector<FieldValueTuple>& data,
vector<FieldValueTuple> data,
const string& op)
{
SWSS_LOG_ENTER();

string alias(keys[0]);
string vrf_name = "";
string vlanId;
string subIntfAlias;
size_t found = alias.find(VLAN_SUB_INTERFACE_SEPARATOR);
if (found != string::npos)
{
// This is a sub interface
// subIntfAlias holds the complete sub interface name
// while alias becomes the parent interface
subIntfAlias = alias;
vlanId = alias.substr(found + 1);
alias = alias.substr(0, found);
}
bool is_lo = !alias.compare(0, strlen(LOOPBACK_PREFIX), LOOPBACK_PREFIX);

string vrf_name = "";
string mtu = "";
string adminStatus = "";
for (auto idx : data)
{
const auto &field = fvField(idx);
const auto &value = fvValue(idx);

if (field == "vnet_name" || field == "vrf_name")
{
vrf_name = value;
}

if (field == "admin_status")
{
adminStatus = value;
}
}

if (op == SET_COMMAND)
Expand All @@ -256,16 +426,73 @@ bool IntfMgr::doIntfGeneralTask(const vector<string>& keys,
SWSS_LOG_ERROR("%s can not change to %s directly, skipping", alias.c_str(), vrf_name.c_str());
return true;
}

if (is_lo)
{
addLoopbackIntf(alias);
}

if (!vrf_name.empty())
{
setIntfVrf(alias, vrf_name);
}
m_appIntfTableProducer.set(alias, data);
m_stateIntfTable.hset(alias, "vrf", vrf_name);

if (!subIntfAlias.empty())
{
if (m_subIntfList.find(subIntfAlias) == m_subIntfList.end())
{
try
{
addHostSubIntf(alias, subIntfAlias, vlanId);
}
catch (const std::runtime_error &e)
{
SWSS_LOG_NOTICE("Sub interface ip link add failure. Runtime error: %s", e.what());
return false;
}

m_subIntfList.insert(subIntfAlias);
}

if (!mtu.empty())
{
try
{
setHostSubIntfMtu(subIntfAlias, mtu);
}
catch (const std::runtime_error &e)
{
SWSS_LOG_NOTICE("Sub interface ip link set mtu failure. Runtime error: %s", e.what());
return false;
}
}
else
{
FieldValueTuple fvTuple("mtu", MTU_INHERITANCE);
data.push_back(fvTuple);
}

if (adminStatus.empty())
{
adminStatus = "up";
FieldValueTuple fvTuple("admin_status", adminStatus);
data.push_back(fvTuple);
}
try
{
setHostSubIntfAdminStatus(subIntfAlias, adminStatus);
}
catch (const std::runtime_error &e)
{
SWSS_LOG_NOTICE("Sub interface ip link set admin status %s failure. Runtime error: %s", adminStatus.c_str(), e.what());
return false;
}

// set STATE_DB port state
setSubIntfStateOk(subIntfAlias);
}
m_appIntfTableProducer.set(subIntfAlias.empty() ? alias : subIntfAlias, data);
m_stateIntfTable.hset(subIntfAlias.empty() ? alias : subIntfAlias, "vrf", vrf_name);
}
else if (op == DEL_COMMAND)
{
Expand All @@ -275,13 +502,24 @@ bool IntfMgr::doIntfGeneralTask(const vector<string>& keys,
{
return false;
}

setIntfVrf(alias, "");

if (is_lo)
{
delLoopbackIntf(alias);
}
m_appIntfTableProducer.del(alias);
m_stateIntfTable.del(alias);

if (!subIntfAlias.empty())
{
removeHostSubIntf(subIntfAlias);
m_subIntfList.erase(subIntfAlias);

removeSubIntfState(subIntfAlias);
}

m_appIntfTableProducer.del(subIntfAlias.empty() ? alias : subIntfAlias);
m_stateIntfTable.del(subIntfAlias.empty() ? alias : subIntfAlias);
}
else
{
Expand All @@ -304,7 +542,7 @@ bool IntfMgr::doIntfAddrTask(const vector<string>& keys,
if (op == SET_COMMAND)
{
/*
* Don't proceed if port/LAG/VLAN and intfGeneral are not ready yet.
* Don't proceed if port/LAG/VLAN/subport and intfGeneral is not ready yet.
* The pending task will be checked periodically and retried.
*/
if (!isIntfStateOk(alias) || !isIntfCreated(alias))
Expand Down
13 changes: 11 additions & 2 deletions cfgmgr/intfmgr.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

#include <map>
#include <string>
#include <set>

namespace swss {

Expand All @@ -18,12 +19,13 @@ class IntfMgr : public Orch

private:
ProducerStateTable m_appIntfTableProducer;
Table m_cfgIntfTable, m_cfgVlanIntfTable;
Table m_statePortTable, m_stateLagTable, m_stateVlanTable, m_stateVrfTable, m_stateIntfTable;

std::set<std::string> m_subIntfList;

void setIntfIp(const std::string &alias, const std::string &opCmd, const IpPrefix &ipPrefix);
void setIntfVrf(const std::string &alias, const std::string &vrfName);
bool doIntfGeneralTask(const std::vector<std::string>& keys, const std::vector<FieldValueTuple>& data, const std::string& op);
bool doIntfGeneralTask(const std::vector<std::string>& keys, std::vector<FieldValueTuple> data, const std::string& op);
bool doIntfAddrTask(const std::vector<std::string>& keys, const std::vector<FieldValueTuple>& data, const std::string& op);
void doTask(Consumer &consumer);
bool isIntfStateOk(const std::string &alias);
Expand All @@ -32,6 +34,13 @@ class IntfMgr : public Orch
int getIntfIpCount(const std::string &alias);
void addLoopbackIntf(const std::string &alias);
void delLoopbackIntf(const std::string &alias);

void addHostSubIntf(const std::string&intf, const std::string &subIntf, const std::string &vlan);
void setHostSubIntfMtu(const std::string &subIntf, const std::string &mtu);
void setHostSubIntfAdminStatus(const std::string &subIntf, const std::string &admin_status);
void removeHostSubIntf(const std::string &subIntf);
void setSubIntfStateOk(const std::string &alias);
void removeSubIntfState(const std::string &alias);
};

}
Expand Down
1 change: 1 addition & 0 deletions cfgmgr/intfmgrd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ int main(int argc, char **argv)
CFG_LAG_INTF_TABLE_NAME,
CFG_VLAN_INTF_TABLE_NAME,
CFG_LOOPBACK_INTERFACE_TABLE_NAME,
CFG_VLAN_SUB_INTF_TABLE_NAME,
};

DBConnector cfgDb(CONFIG_DB, DBConnector::DEFAULT_UNIXSOCKET, 0);
Expand Down
2 changes: 1 addition & 1 deletion orchagent/bufferorch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -598,7 +598,7 @@ task_process_status BufferOrch::processQueue(Consumer &consumer)
}

/*
Input sample "BUFFER_PG_TABLE|Ethernet4,Ethernet45|10-15"
Input sample "BUFFER_PG|Ethernet4,Ethernet45|10-15"
*/
task_process_status BufferOrch::processPriorityGroup(Consumer &consumer)
{
Expand Down
Loading

0 comments on commit 56d66a1

Please sign in to comment.