Skip to content

Commit

Permalink
Added support for EVPN L3 VXLAN as described in the PR sonic-net/SONi…
Browse files Browse the repository at this point in the history
…C#437 (#1267)

VRFMgr Changes to update VRF VNI Map information and notify VRFOrch.
Neighbor Orch changes to Add and Remove Tunnel Nexthops.
Nexthop Key changes to accommodate VNI and Router MAC.
Route Orch changes to Add and Remove Overlay routes, Create and Delete Overlay Nexthops.
Port Orch changes to bring Up / Down Router Interface (IRB Vlan interface) on VRF - VNI Bind / Unbind.
  • Loading branch information
tapashdas authored Dec 18, 2020
1 parent e1dd327 commit b369bb2
Show file tree
Hide file tree
Showing 16 changed files with 880 additions and 44 deletions.
242 changes: 226 additions & 16 deletions cfgmgr/vrfmgr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ VrfMgr::VrfMgr(DBConnector *cfgDb, DBConnector *appDb, DBConnector *stateDb, con
Orch(cfgDb, tableNames),
m_appVrfTableProducer(appDb, APP_VRF_TABLE_NAME),
m_appVnetTableProducer(appDb, APP_VNET_TABLE_NAME),
m_appVxlanVrfTableProducer(appDb, APP_VXLAN_VRF_TABLE_NAME),
m_stateVrfTable(stateDb, STATE_VRF_TABLE_NAME),
m_stateVrfObjectTable(stateDb, STATE_VRF_OBJECT_TABLE_NAME)
{
Expand Down Expand Up @@ -203,23 +204,40 @@ void VrfMgr::doTask(Consumer &consumer)
string op = kfvOp(t);
if (op == SET_COMMAND)
{
if (!setLink(vrfName))
if (consumer.getTableName() == CFG_VXLAN_EVPN_NVO_TABLE_NAME)
{
SWSS_LOG_ERROR("Failed to create vrf netdev %s", vrfName.c_str());
}

vector<FieldValueTuple> fvVector;
fvVector.emplace_back("state", "ok");
m_stateVrfTable.set(vrfName, fvVector);

SWSS_LOG_NOTICE("Created vrf netdev %s", vrfName.c_str());
if (consumer.getTableName() == CFG_VRF_TABLE_NAME)
{
m_appVrfTableProducer.set(vrfName, kfvFieldsValues(t));
doVrfEvpnNvoAddTask(t);
}
else
{
m_appVnetTableProducer.set(vrfName, kfvFieldsValues(t));
if (!setLink(vrfName))
{
SWSS_LOG_ERROR("Failed to create vrf netdev %s", vrfName.c_str());
}

bool status = true;
vector<FieldValueTuple> fvVector;
fvVector.emplace_back("state", "ok");
m_stateVrfTable.set(vrfName, fvVector);

SWSS_LOG_NOTICE("Created vrf netdev %s", vrfName.c_str());
if (consumer.getTableName() == CFG_VRF_TABLE_NAME)
{
status = doVrfVxlanTableCreateTask (t);
if (status == false)
{
SWSS_LOG_ERROR("VRF VNI Map Config Failed");
it = consumer.m_toSync.erase(it);
continue;
}

m_appVrfTableProducer.set(vrfName, kfvFieldsValues(t));

}
else
{
m_appVnetTableProducer.set(vrfName, kfvFieldsValues(t));
}
}
}
else if (op == DEL_COMMAND)
Expand All @@ -229,7 +247,11 @@ void VrfMgr::doTask(Consumer &consumer)
* Now state VRF_TABLE|Vrf represent vrf exist in appDB, if it exist vrf device is always effective.
* VRFOrch add/del state VRF_OBJECT_TABLE|Vrf to represent object existence. VNETOrch is not do so now.
*/
if (consumer.getTableName() == CFG_VRF_TABLE_NAME)
if (consumer.getTableName() == CFG_VXLAN_EVPN_NVO_TABLE_NAME)
{
doVrfEvpnNvoDelTask (t);
}
else if (consumer.getTableName() == CFG_VRF_TABLE_NAME)
{
vector<FieldValueTuple> temp;

Expand All @@ -242,6 +264,7 @@ void VrfMgr::doTask(Consumer &consumer)
continue;
}

doVrfVxlanTableRemoveTask (t);
m_appVrfTableProducer.del(vrfName);
m_stateVrfTable.del(vrfName);
}
Expand All @@ -258,9 +281,12 @@ void VrfMgr::doTask(Consumer &consumer)
m_stateVrfTable.del(vrfName);
}

if (!delLink(vrfName))
if (consumer.getTableName() != CFG_VXLAN_EVPN_NVO_TABLE_NAME)
{
SWSS_LOG_ERROR("Failed to remove vrf netdev %s", vrfName.c_str());
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());
Expand All @@ -273,3 +299,187 @@ void VrfMgr::doTask(Consumer &consumer)
it = consumer.m_toSync.erase(it);
}
}

bool VrfMgr::doVrfEvpnNvoAddTask(const KeyOpFieldsValuesTuple & t)
{
SWSS_LOG_ENTER();
string tunnel_name = "";
const vector<FieldValueTuple>& data = kfvFieldsValues(t);
for (auto idx : data)
{
const auto &field = fvField(idx);
const auto &value = fvValue(idx);

if (field == "source_vtep")
{
tunnel_name = value;
}
}

if (m_evpnVxlanTunnel.empty())
{
m_evpnVxlanTunnel = tunnel_name;
VrfVxlanTableSync(true);
}

SWSS_LOG_INFO("Added evpn nvo tunnel %s", m_evpnVxlanTunnel.c_str());
return true;
}

bool VrfMgr::doVrfEvpnNvoDelTask(const KeyOpFieldsValuesTuple & t)
{
SWSS_LOG_ENTER();

if (!m_evpnVxlanTunnel.empty())
{
VrfVxlanTableSync(false);
m_evpnVxlanTunnel = "";
}

SWSS_LOG_INFO("Removed evpn nvo tunnel %s", m_evpnVxlanTunnel.c_str());
return true;
}

bool VrfMgr::doVrfVxlanTableCreateTask(const KeyOpFieldsValuesTuple & t)
{
SWSS_LOG_ENTER();

auto vrf_name = kfvKey(t);
uint32_t vni = 0, old_vni = 0;
string s_vni = "";
bool add = true;

const vector<FieldValueTuple>& data = kfvFieldsValues(t);
for (auto idx : data)
{
const auto &field = fvField(idx);
const auto &value = fvValue(idx);

if (field == "vni")
{
s_vni = value;
vni = static_cast<uint32_t>(stoul(value));
}
}

if (vni != 0)
{
for (auto itr : m_vrfVniMapTable)
{
if (vni == itr.second)
{
SWSS_LOG_ERROR(" vni %d is already mapped to vrf %s", vni, itr.first.c_str());
return false;
}
}
}

old_vni = getVRFmappedVNI(vrf_name);
SWSS_LOG_INFO("VRF VNI map update vrf %s, vni %d, old_vni %d", vrf_name.c_str(), vni, old_vni);
if (vni != old_vni)
{
if (vni == 0)
{
m_vrfVniMapTable.erase(vrf_name);
s_vni = to_string(old_vni);
add = false;
}
else
{
if (old_vni != 0)
{
SWSS_LOG_ERROR(" vrf %s is already mapped to vni %d", vrf_name.c_str(), old_vni);
return false;
}
m_vrfVniMapTable[vrf_name] = vni;
}

}

if ((vni == 0) && add)
{
return true;
}

SWSS_LOG_INFO("VRF VNI map update vrf %s, s_vni %s, add %d", vrf_name.c_str(), s_vni.c_str(), add);
doVrfVxlanTableUpdate(vrf_name, s_vni, add);
return true;
}

bool VrfMgr::doVrfVxlanTableRemoveTask(const KeyOpFieldsValuesTuple & t)
{
SWSS_LOG_ENTER();

auto vrf_name = kfvKey(t);
uint32_t vni = 0;
string s_vni = "";

vni = getVRFmappedVNI(vrf_name);
SWSS_LOG_INFO("VRF VNI map remove vrf %s, vni %d", vrf_name.c_str(), vni);
if (vni != 0)
{
s_vni = to_string(vni);
doVrfVxlanTableUpdate(vrf_name, s_vni, false);
m_vrfVniMapTable.erase(vrf_name);
}

return true;
}

bool VrfMgr::doVrfVxlanTableUpdate(const string& vrf_name, const string& vni, bool add)
{
SWSS_LOG_ENTER();
string key;

if (m_evpnVxlanTunnel.empty())
{
SWSS_LOG_INFO("NVO Tunnel not present. vrf %s, vni %s, add %d", vrf_name.c_str(), vni.c_str(), add);
return false;
}

key = m_evpnVxlanTunnel + ":" + "evpn_map_" + vni + "_" + vrf_name;

std::vector<FieldValueTuple> fvVector;
FieldValueTuple v1("vni", vni);
FieldValueTuple v2("vrf", vrf_name);
fvVector.push_back(v1);
fvVector.push_back(v2);

SWSS_LOG_INFO("VRF VNI map table update vrf %s, vni %s, add %d", vrf_name.c_str(), vni.c_str(), add);
if (add)
{
m_appVxlanVrfTableProducer.set(key, fvVector);
}
else
{
m_appVxlanVrfTableProducer.del(key);
}

return true;
}

void VrfMgr::VrfVxlanTableSync(bool add)
{
SWSS_LOG_ENTER();
string s_vni = "";

for (auto itr : m_vrfVniMapTable)
{
s_vni = to_string(itr.second);
SWSS_LOG_INFO("vrf %s, vni %s, add %d", (itr.first).c_str(), s_vni.c_str(), add);
doVrfVxlanTableUpdate(itr.first, s_vni, add);
}
}

uint32_t VrfMgr::getVRFmappedVNI(const std::string& vrf_name)
{
if (m_vrfVniMapTable.find(vrf_name) != std::end(m_vrfVniMapTable))
{
return m_vrfVniMapTable.at(vrf_name);
}
else
{
return 0;
}
}

14 changes: 13 additions & 1 deletion cfgmgr/vrfmgr.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,16 @@ using namespace std;

namespace swss {

typedef std::unordered_map<std::string, uint32_t> VRFNameVNIMapTable;

class VrfMgr : public Orch
{
public:
VrfMgr(DBConnector *cfgDb, DBConnector *appDb, DBConnector *stateDb, const std::vector<std::string> &tableNames);
using Orch::doTask;
std::string m_evpnVxlanTunnel;

uint32_t getVRFmappedVNI(const std::string& vrf_name);

private:
bool delLink(const std::string& vrfName);
Expand All @@ -25,13 +30,20 @@ class VrfMgr : public Orch
void recycleTable(uint32_t table);
uint32_t getFreeTable(void);
void handleVnetConfigSet(KeyOpFieldsValuesTuple &t);
bool doVrfEvpnNvoAddTask(const KeyOpFieldsValuesTuple & t);
bool doVrfEvpnNvoDelTask(const KeyOpFieldsValuesTuple & t);
bool doVrfVxlanTableCreateTask(const KeyOpFieldsValuesTuple & t);
bool doVrfVxlanTableRemoveTask(const KeyOpFieldsValuesTuple & t);
bool doVrfVxlanTableUpdate(const string& vrf_name, const string& vni, bool add);
void VrfVxlanTableSync(bool add);
void doTask(Consumer &consumer);

std::map<std::string, uint32_t> m_vrfTableMap;
std::set<uint32_t> m_freeTables;
VRFNameVNIMapTable m_vrfVniMapTable;

Table m_stateVrfTable, m_stateVrfObjectTable;
ProducerStateTable m_appVrfTableProducer, m_appVnetTableProducer;
ProducerStateTable m_appVrfTableProducer, m_appVnetTableProducer, m_appVxlanVrfTableProducer;
};

}
Expand Down
1 change: 1 addition & 0 deletions cfgmgr/vrfmgrd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ int main(int argc, char **argv)
vector<string> cfg_vrf_tables = {
CFG_VRF_TABLE_NAME,
CFG_VNET_TABLE_NAME,
CFG_VXLAN_EVPN_NVO_TABLE_NAME,
};

DBConnector cfgDb("CONFIG_DB", 0);
Expand Down
6 changes: 4 additions & 2 deletions orchagent/mirrororch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,9 @@ MirrorEntry::MirrorEntry(const string& platform) :
greType = 0x88be;
}

string alias = "";
nexthopInfo.prefix = IpPrefix("0.0.0.0/0");
nexthopInfo.nexthop = NextHopKey("0.0.0.0", "");
nexthopInfo.nexthop = NextHopKey("0.0.0.0", alias);
}

MirrorOrch::MirrorOrch(TableConnector stateDbConnector, TableConnector confDbConnector,
Expand Down Expand Up @@ -1185,7 +1186,8 @@ void MirrorOrch::updateNextHop(const NextHopUpdate& update)
}
else
{
session.nexthopInfo.nexthop = NextHopKey("0.0.0.0", "");
string alias = "";
session.nexthopInfo.nexthop = NextHopKey("0.0.0.0", alias);
}

// Update State DB Nexthop
Expand Down
Loading

0 comments on commit b369bb2

Please sign in to comment.