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
  • Loading branch information
tapashdas committed Apr 21, 2020
1 parent 3c8289b commit 16c7f0a
Show file tree
Hide file tree
Showing 15 changed files with 777 additions and 39 deletions.
186 changes: 172 additions & 14 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,32 @@ 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());
}

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));

doVrfVxlanTableCreateTask (t);
}
else
{
m_appVnetTableProducer.set(vrfName, kfvFieldsValues(t));
}
}
}
else if (op == DEL_COMMAND)
Expand All @@ -229,7 +239,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 +256,7 @@ void VrfMgr::doTask(Consumer &consumer)
continue;
}

doVrfVxlanTableRemoveTask (t);
m_appVrfTableProducer.del(vrfName);
m_stateVrfTable.del(vrfName);
}
Expand Down Expand Up @@ -273,3 +288,146 @@ 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_NOTICE("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_NOTICE("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));
}
}

old_vni = getVRFmappedVNI(vrf_name);
SWSS_LOG_NOTICE("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) {
vrf_vni_map_table_.erase(vrf_name);
s_vni = to_string(old_vni);
add = false;
} else {
vrf_vni_map_table_[vrf_name] = vni;
}

}

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

SWSS_LOG_NOTICE("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_NOTICE("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);
vrf_vni_map_table_.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_NOTICE("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_NOTICE("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 : vrf_vni_map_table_)
{
s_vni = to_string(itr.second);
SWSS_LOG_NOTICE("vrf %s, vni %s, add %d", (itr.first).c_str(), s_vni.c_str(), add);
doVrfVxlanTableUpdate(itr.first, s_vni, add);
}
}

20 changes: 19 additions & 1 deletion cfgmgr/vrfmgr.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,22 @@ 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) const
{
if (vrf_vni_map_table_.find(vrf_name) != std::end(vrf_vni_map_table_))
return vrf_vni_map_table_.at(vrf_name);
else
return 0;
}

private:
bool delLink(const std::string& vrfName);
Expand All @@ -25,13 +36,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 vrf_vni_map_table_;

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
93 changes: 91 additions & 2 deletions orchagent/neighorch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include "swssnet.h"
#include "crmorch.h"
#include "routeorch.h"
#include "directory.h"

extern sai_neighbor_api_t* sai_neighbor_api;
extern sai_next_hop_api_t* sai_next_hop_api;
Expand All @@ -12,6 +13,7 @@ extern PortsOrch *gPortsOrch;
extern sai_object_id_t gSwitchId;
extern CrmOrch *gCrmOrch;
extern RouteOrch *gRouteOrch;
extern Directory<Orch*> gDirectory;

const int neighorch_pri = 30;

Expand Down Expand Up @@ -228,6 +230,23 @@ bool NeighOrch::removeNextHop(const IpAddress &ipAddress, const string &alias)
return true;
}

bool NeighOrch::removeOverlayNextHop(const NextHopKey &nexthop)
{
SWSS_LOG_ENTER();

assert(hasNextHop(nexthop));

if (m_syncdNextHops[nexthop].ref_count > 0)
{
SWSS_LOG_ERROR("Failed to remove still referenced next hop %s on %s",
nexthop.ip_address.to_string().c_str(), nexthop.alias.c_str());
return false;
}

m_syncdNextHops.erase(nexthop);
return true;
}

sai_object_id_t NeighOrch::getNextHopId(const NextHopKey &nexthop)
{
assert(hasNextHop(nexthop));
Expand Down Expand Up @@ -425,8 +444,8 @@ bool NeighOrch::addNeighbor(const NeighborEntry &neighborEntry, const MacAddress
return false;
}
}

SWSS_LOG_NOTICE("Created neighbor %s on %s", macAddress.to_string().c_str(), alias.c_str());
SWSS_LOG_NOTICE("Created neighbor ip %s, %s on %s", ip_address.to_string().c_str(),
macAddress.to_string().c_str(), alias.c_str());
m_intfsOrch->increaseRouterIntfsRefCount(alias);

if (neighbor_entry.ip_address.addr_family == SAI_IP_ADDR_FAMILY_IPV4)
Expand Down Expand Up @@ -581,3 +600,73 @@ bool NeighOrch::removeNeighbor(const NeighborEntry &neighborEntry)

return true;
}

sai_object_id_t NeighOrch::addTunnelNextHop(const NextHopKey& nh)
{
SWSS_LOG_ENTER();
sai_object_id_t nh_id = SAI_NULL_OBJECT_ID;

EvpnNvoOrch* evpn_orch = gDirectory.get<EvpnNvoOrch*>();
auto vtep_ptr = evpn_orch->getEVPNVtep();

if(!vtep_ptr)
{
SWSS_LOG_ERROR("Add Tunnel next hop unable to find EVPN VTEP");
return nh_id;
}

auto tun_name = vtep_ptr->getTunnelName();

VxlanTunnelOrch* vxlan_orch = gDirectory.get<VxlanTunnelOrch*>();
IpAddress tnl_dip = nh.ip_address;
nh_id = vxlan_orch->createNextHopTunnel(tun_name, tnl_dip, nh.mac_address, nh.vni);

if (nh_id == SAI_NULL_OBJECT_ID)
{
SWSS_LOG_ERROR("Failed to create Tunnel next hop %s, %s|%d|%s", tun_name.c_str(), nh.ip_address.to_string().c_str(),
nh.vni, nh.mac_address.to_string().c_str());
throw std::runtime_error("NH Tunnel create failed for " + tun_name + " ip " + nh.ip_address.to_string());
}

SWSS_LOG_NOTICE("Created Tunnel next hop %s, %s|%d|%s", tun_name.c_str(), nh.ip_address.to_string().c_str(),
nh.vni, nh.mac_address.to_string().c_str());

NextHopEntry next_hop_entry;
next_hop_entry.next_hop_id = nh_id;
next_hop_entry.ref_count = 0;
next_hop_entry.nh_flags = 0;
m_syncdNextHops[nh] = next_hop_entry;

return nh_id;
}

bool NeighOrch::removeTunnelNextHop(const NextHopKey& nh)
{
SWSS_LOG_ENTER();

EvpnNvoOrch* evpn_orch = gDirectory.get<EvpnNvoOrch*>();
auto vtep_ptr = evpn_orch->getEVPNVtep();

if(!vtep_ptr)
{
SWSS_LOG_ERROR("Remove Tunnel next hop unable to find EVPN VTEP");
return false;
}

auto tun_name = vtep_ptr->getTunnelName();

VxlanTunnelOrch* vxlan_orch = gDirectory.get<VxlanTunnelOrch*>();

IpAddress tnl_dip = nh.ip_address;
if (!vxlan_orch->removeNextHopTunnel(tun_name, tnl_dip, nh.mac_address, nh.vni))
{
SWSS_LOG_ERROR("Failed to remove Tunnel next hop %s, %s|%d|%s", tun_name.c_str(), nh.ip_address.to_string().c_str(),
nh.vni, nh.mac_address.to_string().c_str());
return false;
}

SWSS_LOG_NOTICE("Removed Tunnel next hop %s, %s|%d|%s", tun_name.c_str(), nh.ip_address.to_string().c_str(),
nh.vni, nh.mac_address.to_string().c_str());
return true;
}

Loading

0 comments on commit 16c7f0a

Please sign in to comment.