diff --git a/fpmsyncd/Makefile.am b/fpmsyncd/Makefile.am index 75b0854e95..486f511151 100644 --- a/fpmsyncd/Makefile.am +++ b/fpmsyncd/Makefile.am @@ -12,4 +12,4 @@ fpmsyncd_SOURCES = fpmsyncd.cpp fpmlink.cpp routesync.cpp $(top_srcdir)/warmrest fpmsyncd_CFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) fpmsyncd_CPPFLAGS = $(DBGFLAGS) $(AM_CFLAGS) $(CFLAGS_COMMON) -fpmsyncd_LDADD = -lnl-3 -lnl-route-3 -lswsscommon +fpmsyncd_LDADD = -lnl-3 -lnl-route-3 -lswsscommon -lpthread diff --git a/fpmsyncd/routesync.cpp b/fpmsyncd/routesync.cpp index 7fae01eb3d..962efd0301 100644 --- a/fpmsyncd/routesync.cpp +++ b/fpmsyncd/routesync.cpp @@ -12,6 +12,8 @@ #include "macaddress.h" #include #include +#include +#include using namespace std; using namespace swss; @@ -41,6 +43,13 @@ using namespace swss; #define ETHER_ADDR_STRLEN (3*ETH_ALEN) + +/* helper function for time */ +uint64_t getTimeEpochMsec() { + using namespace std::chrono; + return duration_cast(system_clock::now().time_since_epoch()).count(); +} + RouteSync::RouteSync(RedisPipeline *pipeline) : m_routeTable(pipeline, APP_ROUTE_TABLE_NAME, true), m_vnet_routeTable(pipeline, APP_VNET_RT_TABLE_NAME, true), @@ -51,8 +60,112 @@ RouteSync::RouteSync(RedisPipeline *pipeline) : m_nl_sock = nl_socket_alloc(); nl_connect(m_nl_sock, NETLINK_ROUTE); rtnl_link_alloc_cache(m_nl_sock, AF_UNSPEC, &m_link_cache); + + /* Initailize with defaults*/ + m_routePeriod = 5; + m_countroute = 0; + m_totalRtUpdates = 0; + m_resetRtUpdates = true; + m_runRtUpdateThread = true; + + /* update the time at start */ + m_lastUpdated = getTimeEpochMsec(); + + /* READ THESHOLD CONFIG from BGP_ROUTE_THRESHOLD Table*/ + this->m_cfgDb = new DBConnector("CONFIG_DB", 0); + this->m_cfgRouteThTable = new Table(this->m_cfgDb, "BGP_ROUTE_THRESHOLD"); + + /* WRITE STATS in BGP_ROUTE_UPDATE_FREQUENCY Table STATE DB*/ + this->m_stateDb = new DBConnector("STATE_DB", 0); + this->m_bgpRouteFreqTable = new Table(this->m_stateDb, "BGP_ROUTE_UPDATE_FREQUENCY"); + + /* start route update thread*/ + m_rtUpdateThread = thread(RouteSync::updateRouteThread, this); +} + +RouteSync::~RouteSync() { + delete m_cfgRouteThTable; + delete m_bgpRouteFreqTable; + delete m_cfgDb; + delete m_stateDb; + + /* stop route freq update thread */ + m_runRtUpdateThread = false; + m_rtUpdateThread.join(); +} + +void RouteSync::updateRouteFrequencyStats(bool updateDb=false) { + + /* if updateDb is false, then called just for counter update */ + if (!updateDb) { + ++m_countroute; + ++m_totalRtUpdates; + return; + } + + uint64_t curTime = getTimeEpochMsec(); + if (m_countroute > 0 || m_resetRtUpdates) { + + /* find timediff */ + double timeDiff = (double)(curTime-m_lastUpdated)/1000.00; + + string KEY = "ROUTE_UPDATE_FREQUENCY"; + SWSS_LOG_NOTICE("%lu routes are updated in %.3f secs. Total route updates: %lu\n", \ + m_countroute, timeDiff, m_totalRtUpdates); + + /* create data */ + vector fvVector; + FieldValueTuple tTtUp("TOTAL_ROUTE_UPDATES", std::to_string(m_totalRtUpdates).c_str()); + fvVector.push_back(tTtUp); + FieldValueTuple rtUp("ROUTE_UPDATES", std::to_string(m_countroute).c_str()); + fvVector.push_back(rtUp); + FieldValueTuple tiPe("TIME_PERIOD", std::to_string(timeDiff).c_str()); + fvVector.push_back(tiPe); + + /* if countroute > 0, we need to reset later */ + if (m_countroute > 0) + m_resetRtUpdates = true; + /* else, this is a reset, make it false for next timer */ + else + m_resetRtUpdates = false; + + /* reset counter on update */ + m_countroute = 0; + + /* update state db & set expire TTL */ + m_bgpRouteFreqTable->set(KEY, fvVector); + } + /* change lastUpdated with each timer */ + m_lastUpdated = curTime; + } +void RouteSync::updateRouteThread(RouteSync *sync) { + + while (sync->m_runRtUpdateThread) { + /* Read the Config */ + sync->readBgpRouteThresholdCfg(); + + /* update stats in DB */ + sync->updateRouteFrequencyStats(true); + + /* sleep, thx god, it is not busy */ + std::this_thread::sleep_for(std::chrono::seconds(sync->m_routePeriod)); + } +} + +void RouteSync::readBgpRouteThresholdCfg() { + /* Read Config DB for Threshold Value */ + string value = " "; + string CONFIG_KEY = "ROUTE_UPDATE_THRESHOLD"; + bool ret = m_cfgRouteThTable->hget(CONFIG_KEY, "ROUTE_PERIOD", value); + if (ret) + m_routePeriod = (u_int16_t)std::stoi(value); + + SWSS_LOG_DEBUG("ret:%d value:%s ROUTE_PERIOD: %d\n", ret, value.c_str(), m_routePeriod); +} + + char *RouteSync::prefixMac2Str(char *mac, char *buf, int size) { char *ptr = buf; @@ -443,6 +556,8 @@ void RouteSync::onEvpnRouteMsg(struct nlmsghdr *h, int len) if (nlmsg_type == RTM_DELROUTE) { + /* update route change frequency */ + updateRouteFrequencyStats(); if (!warmRestartInProgress) { m_routeTable.del(destipprefix); @@ -519,6 +634,8 @@ void RouteSync::onEvpnRouteMsg(struct nlmsghdr *h, int len) fvVector.push_back(intf); fvVector.push_back(vni); fvVector.push_back(mac); + /* update route change frequency */ + updateRouteFrequencyStats(); if (!warmRestartInProgress) { @@ -643,6 +760,8 @@ void RouteSync::onRouteMsg(int nlmsg_type, struct nl_object *obj, char *vrf) if (nlmsg_type == RTM_DELROUTE) { + /* update route change frequency */ + updateRouteFrequencyStats(); if (!warmRestartInProgress) { m_routeTable.del(destipprefix); @@ -723,6 +842,9 @@ void RouteSync::onRouteMsg(int nlmsg_type, struct nl_object *obj, char *vrf) fvVector.push_back(nh); fvVector.push_back(idx); + /* update route change frequency */ + updateRouteFrequencyStats(); + if (!warmRestartInProgress) { m_routeTable.set(destipprefix, fvVector); @@ -775,6 +897,9 @@ void RouteSync::onVnetRouteMsg(int nlmsg_type, struct nl_object *obj, string vne if (nlmsg_type == RTM_DELROUTE) { + /* update route change frequency */ + updateRouteFrequencyStats(); + /* Duplicated delete as we do not know if it is a VXLAN tunnel route*/ m_vnet_routeTable.del(vnet_dip); m_vnet_tunnelTable.del(vnet_dip); @@ -813,6 +938,9 @@ void RouteSync::onVnetRouteMsg(int nlmsg_type, struct nl_object *obj, string vne return; } + /* update route change frequency */ + updateRouteFrequencyStats(); + /* Get nexthop lists */ string nexthops = getNextHopGw(route_obj); string ifnames = getNextHopIf(route_obj); diff --git a/fpmsyncd/routesync.h b/fpmsyncd/routesync.h index 71a20f9d66..f312ff2963 100644 --- a/fpmsyncd/routesync.h +++ b/fpmsyncd/routesync.h @@ -7,6 +7,7 @@ #include "warmRestartHelper.h" #include #include +#include using namespace std; @@ -22,10 +23,12 @@ class RouteSync : public NetMsg enum { MAX_ADDR_SIZE = 64 }; RouteSync(RedisPipeline *pipeline); + virtual ~RouteSync(); virtual void onMsg(int nlmsg_type, struct nl_object *obj); virtual void onMsgRaw(struct nlmsghdr *obj); + WarmStartHelper m_warmStartHelper; private: @@ -38,6 +41,44 @@ class RouteSync : public NetMsg struct nl_cache *m_link_cache; struct nl_sock *m_nl_sock; + /* thread for route update frequency */ + thread m_rtUpdateThread; + + /* run thread for route update, till true */ + bool m_runRtUpdateThread; + + /* User Configured Threshold */ + uint16_t m_routePeriod; + + /* reset Route Updates to zero, if true */ + bool m_resetRtUpdates; + + /* Current route updates count */ + uint64_t m_countroute; + + /* Total route updates count */ + uint64_t m_totalRtUpdates; + + /* timestamp for last frequency update */ + uint64_t m_lastUpdated; + + /* Read Config from below Table in CONFIG_DB*/ + DBConnector *m_cfgDb; + Table *m_cfgRouteThTable; + + /* Write Frequency updates to below Table in STATE_DB*/ + DBConnector *m_stateDb; + Table *m_bgpRouteFreqTable; + + /* update route updates, counter\DB */ + void updateRouteFrequencyStats(bool updateDb); + + /* read Config for Route Updates */ + void readBgpRouteThresholdCfg(); + + /* thread for route updates*/ + static void updateRouteThread(RouteSync *sync); + /* Handle regular route (include VRF route) */ void onRouteMsg(int nlmsg_type, struct nl_object *obj, char *vrf);