Skip to content

Commit

Permalink
[chassisorch]: Add everflow feature for chassis (sonic-net#1024)
Browse files Browse the repository at this point in the history
Signed-off-by: Ze Gan <ganze718@gmail.com>
  • Loading branch information
Pterosaur authored and stcheng committed Oct 10, 2019
1 parent 5b13387 commit e658b64
Show file tree
Hide file tree
Showing 6 changed files with 347 additions and 2 deletions.
3 changes: 2 additions & 1 deletion orchagent/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,8 @@ orchagent_SOURCES = \
dtelorch.cpp \
flexcounterorch.cpp \
watermarkorch.cpp \
policerorch.cpp
policerorch.cpp \
chassisorch.cpp

orchagent_CFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI)
orchagent_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_SAI)
Expand Down
74 changes: 74 additions & 0 deletions orchagent/chassisorch.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
#include "chassisorch.h"
#include "routeorch.h"

ChassisOrch::ChassisOrch(
DBConnector* cfgDb,
DBConnector* applDb,
const std::vector<std::string>& tableNames,
VNetRouteOrch* vNetRouteOrch) :
Orch(cfgDb, tableNames),
m_passThroughRouteTable(applDb, APP_PASS_THROUGH_ROUTE_TABLE_NAME),
m_vNetRouteOrch(vNetRouteOrch)
{
}

void ChassisOrch::update(SubjectType type, void* ctx)
{
SWSS_LOG_ENTER();
VNetNextHopUpdate* updateInfo = reinterpret_cast<VNetNextHopUpdate*>(ctx);
if (updateInfo->op == SET_COMMAND)
{
addRouteToPassThroughRouteTable(*updateInfo);
}
else
{
deleteRoutePassThroughRouteTable(*updateInfo);
}
}

void ChassisOrch::addRouteToPassThroughRouteTable(const VNetNextHopUpdate& update)
{
SWSS_LOG_ENTER();

std::vector<FieldValueTuple> fvVector;
fvVector.emplace_back("redistribute", "true");
fvVector.emplace_back("next_vrf_name", update.vnet);
fvVector.emplace_back("next_hop_ip", update.nexthop.ips.to_string());
fvVector.emplace_back("ifname", update.nexthop.ifname);
fvVector.emplace_back("source", "CHASSIS_ORCH");
const std::string everflow_route = IpPrefix(update.destination.to_string()).to_string();
m_passThroughRouteTable.set(everflow_route, fvVector);
}

void ChassisOrch::deleteRoutePassThroughRouteTable(const VNetNextHopUpdate& update)
{
SWSS_LOG_ENTER();
const std::string everflow_route = IpPrefix(update.destination.to_string()).to_string();
m_passThroughRouteTable.del(everflow_route);
}

void ChassisOrch::doTask(Consumer &consumer)
{
SWSS_LOG_ENTER();

const std::string & tableName = consumer.getTableName();
auto it = consumer.m_toSync.begin();
while (it != consumer.m_toSync.end())
{
auto t = it->second;
const std::string & op = kfvOp(t);
const std::string & ip = kfvKey(t);

if (op == SET_COMMAND)
{
m_vNetRouteOrch->attach(this, ip);
}
else
{
m_vNetRouteOrch->detach(this, ip);
}
it = consumer.m_toSync.erase(it);
}

}

36 changes: 36 additions & 0 deletions orchagent/chassisorch.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#ifndef SWSS_CHASSISORCH_H
#define SWSS_CHASSISORCH_H

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

#include "dbconnector.h"
#include "producerstatetable.h"
#include "orch.h"
#include "observer.h"
#include "vnetorch.h"

class ChassisOrch : public Orch, public Observer
{
public:
ChassisOrch(
DBConnector* cfgDb,
DBConnector *applDb,
const std::vector<std::string> &tableNames,
VNetRouteOrch * vNetRouteOrch);

private:

void update(SubjectType, void*);
void addRouteToPassThroughRouteTable(const VNetNextHopUpdate& update);
void deleteRoutePassThroughRouteTable(const VNetNextHopUpdate& update);

virtual void doTask(Consumer &consumer);

Table m_passThroughRouteTable;
VNetRouteOrch* m_vNetRouteOrch;
};

#endif
8 changes: 8 additions & 0 deletions orchagent/orchdaemon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

#define SAI_SWITCH_ATTR_CUSTOM_RANGE_BASE SAI_SWITCH_ATTR_CUSTOM_RANGE_START
#include "sairedis.h"
#include "chassisorch.h"

using namespace std;
using namespace swss;
Expand Down Expand Up @@ -112,6 +113,12 @@ bool OrchDaemon::init()
VRFOrch *vrf_orch = new VRFOrch(m_applDb, APP_VRF_TABLE_NAME);
gDirectory.set(vrf_orch);

const vector<string> chassis_frontend_tables = {
CFG_PASS_THROUGH_ROUTE_TABLE_NAME,
};
ChassisOrch* chassis_frontend_orch = new ChassisOrch(m_configDb, m_applDb, chassis_frontend_tables, vnet_rt_orch);
gDirectory.set(chassis_frontend_orch);

gIntfsOrch = new IntfsOrch(m_applDb, APP_INTF_TABLE_NAME, vrf_orch);
gNeighOrch = new NeighOrch(m_applDb, APP_NEIGH_TABLE_NAME, gIntfsOrch);
gRouteOrch = new RouteOrch(m_applDb, APP_ROUTE_TABLE_NAME, gNeighOrch);
Expand Down Expand Up @@ -225,6 +232,7 @@ bool OrchDaemon::init()
m_orchList.push_back(gFdbOrch);
m_orchList.push_back(mirror_orch);
m_orchList.push_back(gAclOrch);
m_orchList.push_back(chassis_frontend_orch);
m_orchList.push_back(vrf_orch);
m_orchList.push_back(vxlan_tunnel_orch);
m_orchList.push_back(vxlan_tunnel_map_orch);
Expand Down
195 changes: 195 additions & 0 deletions orchagent/vnetorch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <unordered_set>
#include <exception>
#include <inttypes.h>
#include <algorithm>

#include "sai.h"
#include "saiextensions.h"
Expand Down Expand Up @@ -1911,6 +1912,15 @@ bool VNetRouteOrch::handleRoutes(const Request& request)

SWSS_LOG_INFO("VNET-RT '%s' op '%s' for ip %s", vnet_name.c_str(),
op.c_str(), ip_pfx.to_string().c_str());

if (op == SET_COMMAND)
{
addRoute(vnet_name, ip_pfx, nh);
}
else
{
delRoute(ip_pfx);
}

if (vnet_orch_->isVnetExecVrf())
{
Expand All @@ -1924,6 +1934,191 @@ bool VNetRouteOrch::handleRoutes(const Request& request)
return true;
}

void VNetRouteOrch::attach(Observer* observer, const IpAddress& dstAddr)
{
SWSS_LOG_ENTER();

auto insert_result = next_hop_observers_.emplace(dstAddr, VNetNextHopObserverEntry());
auto observerEntry = insert_result.first;
/* Create a new observer entry if no current observer is observing this
* IP address */
if (insert_result.second)
{
/* Find the prefixes that cover the destination IP */
for (auto route : syncd_routes_)
{
if (route.first.isAddressInSubnet(dstAddr))
{
SWSS_LOG_INFO("Prefix %s covers destination address",
route.first.to_string().c_str());

observerEntry->second.routeTable.emplace(
route.first,
route.second
);
}
}
}

observerEntry->second.observers.push_back(observer);

auto bestRoute = observerEntry->second.routeTable.rbegin();
if (bestRoute != observerEntry->second.routeTable.rend())
{
SWSS_LOG_NOTICE("Attached next hop observer of route %s for destination IP %s",
bestRoute->first.to_string().c_str(),
dstAddr.to_string().c_str());
for (auto vnetEntry : bestRoute->second)
{
VNetNextHopUpdate update =
{
SET_COMMAND,
vnetEntry.first, // vnet name
dstAddr, // destination
bestRoute->first, // prefix
vnetEntry.second // nexthop
};
observer->update(SUBJECT_TYPE_NEXTHOP_CHANGE, reinterpret_cast<void*>(&update));
}
}
}

void VNetRouteOrch::detach(Observer* observer, const IpAddress& dstAddr)
{
SWSS_LOG_ENTER();
auto observerEntry = next_hop_observers_.find(dstAddr);

if (observerEntry == next_hop_observers_.end())
{
SWSS_LOG_ERROR("Failed to detach observer for %s. Entry not found.", dstAddr.to_string().c_str());
assert(false);
return;
}

auto iter = std::find(
observerEntry->second.observers.begin(),
observerEntry->second.observers.end(),
observer);
if (iter == observerEntry->second.observers.end())
{
SWSS_LOG_ERROR("Failed to detach observer for %s. Observer not found.", dstAddr.to_string().c_str());
assert(false);
return;
}

auto bestRoute = observerEntry->second.routeTable.rbegin();
if (bestRoute != observerEntry->second.routeTable.rend())
{
for (auto vnetEntry : bestRoute->second)
{
VNetNextHopUpdate update =
{
DEL_COMMAND,
vnetEntry.first, // vnet name
dstAddr, // destination
bestRoute->first, // prefix
vnetEntry.second // nexthop
};
observer->update(SUBJECT_TYPE_NEXTHOP_CHANGE, reinterpret_cast<void*>(&update));
}
}
next_hop_observers_.erase(observerEntry);
}

void VNetRouteOrch::addRoute(const std::string& vnet, const IpPrefix& ipPrefix, const nextHop& nh)
{
SWSS_LOG_ENTER();
for (auto& next_hop_observer : next_hop_observers_)
{
if (ipPrefix.isAddressInSubnet(next_hop_observer.first))
{
auto route_insert_result = next_hop_observer.second.routeTable.emplace(ipPrefix, VNetEntry());

auto vnet_result_result = route_insert_result.first->second.emplace(vnet, nh);
if (!vnet_result_result.second)
{
if (vnet_result_result.first->second.ips == nh.ips
&& vnet_result_result.first->second.ifname == nh.ifname)
{
continue;
}
vnet_result_result.first->second = nh;
}

// If the inserted route is the best route. (Table should not be empty. Because we inserted a new entry above)
if (route_insert_result.first == --next_hop_observer.second.routeTable.end())
{
VNetNextHopUpdate update =
{
SET_COMMAND,
vnet, // vnet name
next_hop_observer.first, // destination
ipPrefix, // prefix
nh // nexthop
};
for (auto& observer : next_hop_observer.second.observers)
{
observer->update(SUBJECT_TYPE_NEXTHOP_CHANGE, reinterpret_cast<void*>(&update));
}
}
}
}
syncd_routes_.emplace(ipPrefix, VNetEntry()).first->second[vnet] = nh;
}

void VNetRouteOrch::delRoute(const IpPrefix& ipPrefix)
{
SWSS_LOG_ENTER();

auto route_itr = syncd_routes_.find(ipPrefix);
if (route_itr == syncd_routes_.end())
{
SWSS_LOG_ERROR("Failed to find route %s.", ipPrefix.to_string().c_str());
assert(false);
return;
}
auto next_hop_observer = next_hop_observers_.begin();
while(next_hop_observer != next_hop_observers_.end())
{
if (ipPrefix.isAddressInSubnet(next_hop_observer->first))
{
auto itr = next_hop_observer->second.routeTable.find(ipPrefix);
if ( itr == next_hop_observer->second.routeTable.end())
{
SWSS_LOG_ERROR(
"Failed to find any ip(%s) belong to this route(%s).",
next_hop_observer->first.to_string().c_str(),
ipPrefix.to_string().c_str());
assert(false);
continue;
}
if (itr->second.empty())
{
continue;
}
for (auto& observer : next_hop_observer->second.observers)
{
VNetNextHopUpdate update = {
DEL_COMMAND,
itr->second.rbegin()->first, // vnet name
next_hop_observer->first, // destination
itr->first, // prefix
itr->second.rbegin()->second // nexthop
};
observer->update(SUBJECT_TYPE_NEXTHOP_CHANGE, reinterpret_cast<void*>(&update));
}
next_hop_observer->second.routeTable.erase(itr);
if (next_hop_observer->second.routeTable.empty())
{
next_hop_observer = next_hop_observers_.erase(next_hop_observer);
continue;
}
}
next_hop_observer++;
}
syncd_routes_.erase(route_itr);
}

bool VNetRouteOrch::handleTunnel(const Request& request)
{
SWSS_LOG_ENTER();
Expand Down
Loading

0 comments on commit e658b64

Please sign in to comment.