LCOV - code coverage report
Current view: top level - bgp/routing-instance - routepath_replicator.cc (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 383 408 93.9 %
Date: 2026-06-08 02:02:55 Functions: 40 43 93.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
       3             :  */
       4             : 
       5             : #include "bgp/routing-instance/routepath_replicator.h"
       6             : 
       7             : #include <boost/foreach.hpp>
       8             : 
       9             : #include <utility>
      10             : 
      11             : #include "base/set_util.h"
      12             : #include "base/task_annotations.h"
      13             : #include "base/task_trigger.h"
      14             : #include "bgp/bgp_config.h"
      15             : #include "bgp/bgp_log.h"
      16             : #include "bgp/bgp_route.h"
      17             : #include "bgp/bgp_server.h"
      18             : #include "bgp/origin-vn/origin_vn.h"
      19             : #include "bgp/routing-instance/path_resolver.h"
      20             : #include "bgp/routing-instance/routing_instance.h"
      21             : #include "bgp/routing-instance/rtarget_group_mgr.h"
      22             : #include "bgp/routing-instance/routing_instance_analytics_types.h"
      23             : 
      24             : using std::ostringstream;
      25             : using std::make_pair;
      26             : using std::pair;
      27             : using std::string;
      28             : using std::vector;
      29             : 
      30             : //
      31             : // RoutePathReplication trace macro. Optionally logs the server name as well for
      32             : // easier debugging in multi server unit tests
      33             : //
      34             : #define RPR_TRACE(obj, ...)                                                    \
      35             : do {                                                                           \
      36             :     if (LoggingDisabled()) break;                                              \
      37             :     bgp_log_test::LogServerName(server());                                     \
      38             :     Rpr##obj##Log::Send("RoutingInstance",                                     \
      39             :             SandeshLevel::SYS_DEBUG, __FILE__, __LINE__, __VA_ARGS__);         \
      40             :     Rpr##obj::TraceMsg(trace_buf_, __FILE__, __LINE__, __VA_ARGS__);           \
      41             : } while (false)
      42             : 
      43             : #define RPR_TRACE_ONLY(obj, ...)                                               \
      44             : do {                                                                           \
      45             :     if (LoggingDisabled()) break;                                              \
      46             :     bgp_log_test::LogServerName(server());                                     \
      47             :     Rpr##obj::TraceMsg(trace_buf_, __FILE__, __LINE__, __VA_ARGS__);           \
      48             : } while (false)
      49             : 
      50             : class TableState::DeleteActor : public LifetimeActor {
      51             : public:
      52      254199 :     explicit DeleteActor(TableState *ts)
      53      254199 :         : LifetimeActor(ts->replicator()->server()->lifetime_manager()),
      54      254199 :           ts_(ts) {
      55      254203 :     }
      56             : 
      57      254286 :     virtual bool MayDelete() const {
      58      254286 :         return ts_->MayDelete();
      59             :     }
      60             : 
      61      254205 :     virtual void Shutdown() {
      62      254205 :     }
      63             : 
      64      254205 :     virtual void Destroy() {
      65      254205 :         ts_->replicator()->DeleteTableState(ts_->table());
      66      254205 :     }
      67             : 
      68             : private:
      69             :     TableState *ts_;
      70             : };
      71             : 
      72      254200 : TableState::TableState(RoutePathReplicator *replicator, BgpTable *table)
      73      254200 :     : replicator_(replicator),
      74      254200 :       table_(table),
      75      254200 :       listener_id_(DBTableBase::kInvalidId),
      76      254200 :       deleter_(new DeleteActor(this)),
      77      254201 :       table_delete_ref_(this, table->deleter()) {
      78      254192 :     assert(table->deleter() != NULL);
      79      254191 : }
      80             : 
      81      254205 : TableState::~TableState() {
      82      254205 :     if (walk_ref() != NULL) {
      83       22611 :         table()->ReleaseWalker(walk_ref());
      84             :     }
      85      254205 : }
      86             : 
      87      254205 : void TableState::ManagedDelete() {
      88      254205 :     deleter()->Delete();
      89      254205 : }
      90             : 
      91           0 : bool TableState::deleted() const {
      92           0 :     return deleter()->IsDeleted();
      93             : }
      94             : 
      95      903367 : LifetimeActor *TableState::deleter() {
      96      903367 :     return deleter_.get();
      97             : }
      98             : 
      99           0 : const LifetimeActor *TableState::deleter() const {
     100           0 :     return deleter_.get();
     101             : }
     102             : 
     103      254286 : bool TableState::MayDelete() const {
     104      531196 :     if (list_.empty() && !route_count() &&
     105      276910 :         ((walk_ref() == NULL) || !walk_ref()->walk_is_active()))
     106      254205 :         return true;
     107          81 :     return false;
     108             : }
     109             : 
     110      629998 : void TableState::RetryDelete() {
     111      629998 :     if (!deleter()->IsDeleted())
     112      610729 :         return;
     113       19169 :     deleter()->RetryDelete();
     114             : }
     115             : 
     116      668197 : void TableState::AddGroup(RtGroup *group) {
     117      668197 :     list_.insert(group);
     118      668316 : }
     119             : 
     120      668345 : void TableState::RemoveGroup(RtGroup *group) {
     121      668345 :     list_.erase(group);
     122      668345 : }
     123             : 
     124      429494 : const RtGroup *TableState::FindGroup(RtGroup *group) const {
     125      429494 :     GroupList::const_iterator it = list_.find(group);
     126      429476 :     return (it != list_.end() ? *it : NULL);
     127             : }
     128             : 
     129      254297 : uint32_t TableState::route_count() const {
     130      254297 :     return table_->GetDBStateCount(listener_id());
     131             : }
     132             : 
     133     1044883 : RtReplicated::RtReplicated(RoutePathReplicator *replicator)
     134     1044883 :     : replicator_(replicator) {
     135     1044869 : }
     136             : 
     137      517698 : void RtReplicated::AddRouteInfo(BgpTable *table, BgpRoute *rt,
     138             :     ReplicatedRtPathList::const_iterator it) {
     139      517698 :     pair<ReplicatedRtPathList::iterator, bool> result;
     140      517704 :     result = replicate_list_.insert(*it);
     141      517734 :     assert(result.second);
     142      517734 : }
     143             : 
     144      516546 : void RtReplicated::DeleteRouteInfo(BgpTable *table, BgpRoute *rt,
     145             :     ReplicatedRtPathList::const_iterator it) {
     146      516546 :     replicator_->DeleteSecondaryPath(table, rt, *it);
     147      517039 :     replicate_list_.erase(it);
     148      517392 : }
     149             : 
     150             : //
     151             : // Return the list of secondary table names for the given primary path.
     152             : // We go through all SecondaryRouteInfos and skip the ones that don't
     153             : // match the primary path.
     154             : //
     155         281 : vector<string> RtReplicated::GetTableNameList(const BgpPath *path) const {
     156         281 :     vector<string> table_list;
     157        1367 :     BOOST_FOREACH(const SecondaryRouteInfo &rinfo, replicate_list_) {
     158         543 :         if (rinfo.peer_ != path->GetPeer())
     159           0 :             continue;
     160         543 :         if (rinfo.path_id_ != path->GetPathId())
     161          16 :             continue;
     162         527 :         if (rinfo.src_ != path->GetSource())
     163           0 :             continue;
     164         527 :         table_list.push_back(rinfo.table_->name());
     165             :     }
     166         281 :     return table_list;
     167           0 : }
     168             : 
     169       48710 : RoutePathReplicator::RoutePathReplicator(BgpServer *server,
     170       48710 :     Address::Family family)
     171       48710 :     : server_(server),
     172       48710 :       family_(family),
     173       48710 :       vpn_table_(NULL),
     174       48710 :       trace_buf_(SandeshTraceBufferCreate("RoutePathReplicator", 500)) {
     175       48710 : }
     176             : 
     177       97420 : RoutePathReplicator::~RoutePathReplicator() {
     178       48710 :     assert(table_state_list_.empty());
     179       97420 : }
     180             : 
     181       41135 : void RoutePathReplicator::Initialize() {
     182       41135 :     assert(!vpn_table_);
     183       41135 :     RoutingInstanceMgr *mgr = server_->routing_instance_mgr();
     184       41135 :     assert(mgr);
     185       41135 :     RoutingInstance *master = mgr->GetDefaultRoutingInstance();
     186       41135 :     assert(master);
     187       41135 :     vpn_table_ = master->GetTable(family_);
     188       41135 :     assert(vpn_table_);
     189       41135 :     assert(AddTableState(vpn_table_));
     190       41135 : }
     191             : 
     192      709457 : TableState *RoutePathReplicator::AddTableState(BgpTable *table,
     193             :     RtGroup *group) {
     194      709457 :     assert(table->IsVpnTable() || group);
     195             : 
     196      709418 :     TableStateList::iterator loc = table_state_list_.find(table);
     197      709225 :     if (loc == table_state_list_.end()) {
     198      254195 :         TableState *ts = new TableState(this, table);
     199      254191 :         DBTableBase::ListenerId id = table->Register(
     200             :             boost::bind(&RoutePathReplicator::RouteListener, this, ts, _1, _2),
     201             :             "RoutePathReplicator");
     202      254182 :         ts->set_listener_id(id);
     203      254179 :         if (group)
     204      213045 :             ts->AddGroup(group);
     205      254201 :         table_state_list_.insert(make_pair(table, ts));
     206      254198 :         RPR_TRACE(RegTable, table->name());
     207      254198 :         return ts;
     208             :     } else {
     209      455159 :         assert(group);
     210      455159 :         TableState *ts = loc->second;
     211      455161 :         ts->AddGroup(group);
     212      455264 :         return ts;
     213             :     }
     214             : }
     215             : 
     216      668345 : void RoutePathReplicator::RemoveTableState(BgpTable *table, RtGroup *group) {
     217      668345 :     TableState *ts = FindTableState(table);
     218      668345 :     assert(ts);
     219      668345 :     ts->RemoveGroup(group);
     220      668345 : }
     221             : 
     222      254205 : void RoutePathReplicator::DeleteTableState(BgpTable *table) {
     223      254205 :     TableState *ts = FindTableState(table);
     224      254205 :     assert(ts);
     225      254205 :     RPR_TRACE(UnregTable, table->name());
     226      254205 :     table->Unregister(ts->listener_id());
     227      254205 :     table_state_list_.erase(table);
     228      254205 :     delete ts;
     229      254205 : }
     230             : 
     231     1858374 : TableState *RoutePathReplicator::FindTableState(BgpTable *table) {
     232     1858374 :     TableStateList::iterator loc = table_state_list_.find(table);
     233     1858289 :     return (loc != table_state_list_.end() ? loc->second : NULL);
     234             : }
     235             : 
     236        5640 : const TableState *RoutePathReplicator::FindTableState(
     237             :     const BgpTable *table) const {
     238             :     TableStateList::const_iterator loc =
     239        5640 :         table_state_list_.find(const_cast<BgpTable *>(table));
     240        5631 :     return (loc != table_state_list_.end() ? loc->second : NULL);
     241             : }
     242             : 
     243             : void
     244       51352 : RoutePathReplicator::RequestWalk(BgpTable *table) {
     245       51352 :     CHECK_CONCURRENCY("bgp::Config", "bgp::ConfigHelper");
     246       51352 :     TableState *ts = FindTableState(table);
     247       51352 :     assert(ts);
     248       51352 :     if (!ts->walk_ref()) {
     249             :         DBTable::DBTableWalkRef walk_ref = table->AllocWalker(
     250             :           boost::bind(&RoutePathReplicator::RouteListener, this, ts, _1, _2),
     251       45222 :           boost::bind(&RoutePathReplicator::BulkReplicationDone, this, _2));
     252       22611 :         table->WalkTable(walk_ref);
     253       22611 :         ts->set_walk_ref(walk_ref);
     254       22611 :     } else {
     255       28741 :         table->WalkAgain(ts->walk_ref());
     256             :     }
     257       51352 : }
     258             : 
     259             : void
     260       24593 : RoutePathReplicator::BulkReplicationDone(DBTableBase *dbtable) {
     261       24593 :     CHECK_CONCURRENCY("db::Walker");
     262       24593 :     BgpTable *table = static_cast<BgpTable *>(dbtable);
     263       24593 :     RPR_TRACE(WalkDone, table->name());
     264       24593 :     TableState *ts = FindTableState(table);
     265       24593 :     ts->RetryDelete();
     266       24593 : }
     267             : 
     268      429942 : void RoutePathReplicator::JoinVpnTable(RtGroup *group) {
     269      429942 :     CHECK_CONCURRENCY("bgp::Config", "bgp::ConfigHelper");
     270      429959 :     TableState *vpn_ts = FindTableState(vpn_table_);
     271      429860 :     if (!vpn_ts || vpn_ts->FindGroup(group))
     272         370 :         return;
     273      429466 :     RPR_TRACE(TableJoin, vpn_table_->name(), group->rt().ToString(), true);
     274      429605 :     group->AddImportTable(family(), vpn_table_);
     275      429720 :     RPR_TRACE(TableJoin, vpn_table_->name(), group->rt().ToString(), false);
     276      429714 :     group->AddExportTable(family(), vpn_table_);
     277      429719 :     AddTableState(vpn_table_, group);
     278             : }
     279             : 
     280      429909 : void RoutePathReplicator::LeaveVpnTable(RtGroup *group) {
     281      429909 :     CHECK_CONCURRENCY("bgp::Config", "bgp::ConfigHelper");
     282      429908 :     TableState *vpn_ts = FindTableState(vpn_table_);
     283      429907 :     if (!vpn_ts)
     284         185 :         return;
     285      429722 :     RPR_TRACE(TableLeave, vpn_table_->name(), group->rt().ToString(), true);
     286      429723 :     group->RemoveImportTable(family(), vpn_table_);
     287      429725 :     RPR_TRACE(TableLeave, vpn_table_->name(), group->rt().ToString(), false);
     288      429725 :     group->RemoveExportTable(family(), vpn_table_);
     289      429725 :     RemoveTableState(vpn_table_, group);
     290             : }
     291             : 
     292             : //
     293             : // Add a given BgpTable to RtGroup of given RouteTarget.
     294             : // It will create a new RtGroup if none exists.
     295             : // In case of export RouteTarget, create TableState if it doesn't exist.
     296             : //
     297      927921 : void RoutePathReplicator::Join(BgpTable *table, const RouteTarget &rt,
     298             :                                bool import) {
     299      927921 :     CHECK_CONCURRENCY("bgp::Config", "bgp::ConfigHelper");
     300             : 
     301      927732 :     std::scoped_lock lock(mutex_);
     302      928439 :     RPR_TRACE(TableJoin, table->name(), rt.ToString(), import);
     303             : 
     304      928439 :     bool first = false;
     305      928439 :     RtGroup *group = server()->rtarget_group_mgr()->LocateRtGroup(rt);
     306      928560 :     if (import) {
     307      689940 :         first = group->AddImportTable(family(), table);
     308      689935 :         if (group->HasDepRoutes())
     309         100 :             server()->rtarget_group_mgr()->NotifyRtGroup(rt);
     310      689856 :         if (family_ == Address::INETVPN)
     311      137989 :             server_->NotifyAllStaticRoutes();
     312     1338203 :         BOOST_FOREACH(BgpTable *sec_table, group->GetExportTables(family())) {
     313      324160 :             if (sec_table->IsVpnTable() || sec_table->empty())
     314      322974 :                 continue;
     315        1194 :             RequestWalk(sec_table);
     316             :         }
     317             :     } else {
     318      238620 :         first = group->AddExportTable(family(), table);
     319      238612 :         AddTableState(table, group);
     320      238612 :         if (!table->empty()) {
     321          59 :             RequestWalk(table);
     322             :         }
     323             :     }
     324             : 
     325             :     // Join the vpn table when group is created.
     326      928214 :     if (first)
     327      429946 :         JoinVpnTable(group);
     328      928344 : }
     329             : 
     330             : //
     331             : // Remove a BgpTable from RtGroup of given RouteTarget.
     332             : // If the last group is going away, the RtGroup will be removed
     333             : // In case of export RouteTarget, trigger remove of TableState appropriate.
     334             : //
     335      928563 : void RoutePathReplicator::Leave(BgpTable *table, const RouteTarget &rt,
     336             :                                 bool import) {
     337      928563 :     CHECK_CONCURRENCY("bgp::Config", "bgp::ConfigHelper");
     338             : 
     339      928562 :     std::scoped_lock lock(mutex_);
     340      928565 :     RtGroup *group = server()->rtarget_group_mgr()->GetRtGroup(rt);
     341      928565 :     assert(group);
     342      928565 :     RPR_TRACE(TableLeave, table->name(), rt.ToString(), import);
     343             : 
     344      928565 :     if (import) {
     345      689945 :         group->RemoveImportTable(family(), table);
     346      689937 :         if (group->HasDepRoutes())
     347      132335 :             server()->rtarget_group_mgr()->NotifyRtGroup(rt);
     348      689937 :         if (family_ == Address::INETVPN)
     349      137989 :             server_->NotifyAllStaticRoutes();
     350     2674117 :         BOOST_FOREACH(BgpTable *sec_table, group->GetExportTables(family())) {
     351      992091 :             if (sec_table->IsVpnTable() || sec_table->empty())
     352      965176 :                 continue;
     353       26914 :             RequestWalk(sec_table);
     354             :         }
     355             :     } else {
     356      238620 :         group->RemoveExportTable(family(), table);
     357      238620 :         RemoveTableState(table, group);
     358      238620 :         if (!table->empty()) {
     359       23164 :             RequestWalk(table);
     360             :         }
     361             :     }
     362             : 
     363             :     // Leave the vpn table when the last VRF has left the group.
     364      928554 :     if (!group->HasVrfTables(family())) {
     365      429909 :         LeaveVpnTable(group);
     366      429910 :         server()->rtarget_group_mgr()->RemoveRtGroup(rt);
     367             :     }
     368      928555 : }
     369             : 
     370     1431182 : void RoutePathReplicator::DBStateSync(BgpTable *table, TableState *ts,
     371             :     BgpRoute *rt, RtReplicated *dbstate,
     372             :     const RtReplicated::ReplicatedRtPathList *future) {
     373     1431182 :     set_synchronize(dbstate->GetMutableList(), future,
     374             :         boost::bind(&RtReplicated::AddRouteInfo, dbstate, table, rt, _1),
     375             :         boost::bind(&RtReplicated::DeleteRouteInfo, dbstate, table, rt, _1));
     376             : 
     377     1430925 :     if (dbstate->GetList().empty()) {
     378     1044834 :         rt->ClearState(table, ts->listener_id());
     379     1045525 :         delete dbstate;
     380     1045209 :         if (table->GetDBStateCount(ts->listener_id()) == 0)
     381      605432 :             ts->RetryDelete();
     382             :     }
     383     1431457 : }
     384             : 
     385      222403 : static ExtCommunityPtr UpdateOriginVn(BgpServer *server,
     386             :                                       const ExtCommunity *ext_community,
     387             :                                       int vn_index) {
     388      222403 :     as_t asn = server->autonomous_system();
     389      222405 :     ExtCommunityPtr extcomm_ptr;
     390      222405 :     if (vn_index) {
     391       54135 :         if (asn > AS2_MAX && vn_index > 0xffff) {
     392           0 :             OriginVn origin_vn(asn, AS_TRANS);
     393           0 :             extcomm_ptr = server->extcomm_db()->ReplaceOriginVnAndLocate(
     394           0 :                 ext_community, origin_vn.GetExtCommunity());
     395           0 :             OriginVn origin_vn2(AS_TRANS, vn_index);
     396           0 :             extcomm_ptr = server->extcomm_db()->AppendAndLocate(
     397           0 :                 extcomm_ptr.get(), origin_vn2.GetExtCommunity());
     398           0 :         } else {
     399       54135 :             OriginVn origin_vn(asn, vn_index);
     400      162412 :             extcomm_ptr = server->extcomm_db()->ReplaceOriginVnAndLocate(
     401      108277 :                 ext_community, origin_vn.GetExtCommunity());
     402       54142 :             return extcomm_ptr;
     403             :         }
     404             :     }
     405      168270 :     extcomm_ptr = server->extcomm_db()->RemoveOriginVnAndLocate(ext_community);
     406      168312 :     return extcomm_ptr;
     407           0 : }
     408             : 
     409             : //
     410             : // Update the ExtCommunity with the RouteTargets from the export list
     411             : // and the OriginVn. The OriginVn is derived from the RouteTargets in
     412             : // vpn routes.
     413             : //
     414      514757 : static ExtCommunityPtr UpdateExtCommunity(BgpServer *server,
     415             :         const RoutingInstance *rtinstance, const ExtCommunity *ext_community,
     416             :         const ExtCommunity::ExtCommunityList &export_list) {
     417             :     // Add RouteTargets exported by the instance for a non-master instance.
     418      514757 :     ExtCommunityPtr extcomm_ptr;
     419      514757 :     if (!rtinstance->IsMasterRoutingInstance()) {
     420             :         extcomm_ptr =
     421      323009 :             server->extcomm_db()->AppendAndLocate(ext_community, export_list);
     422      323099 :         return extcomm_ptr;
     423             :     }
     424             : 
     425             :     // Bail if we have a vpn route without extended communities.
     426      191745 :     if (!ext_community)
     427        1053 :         return ExtCommunityPtr(NULL);
     428             : 
     429             :     // Nothing to do if we already have the OriginVn community with our AS
     430             :     // or with a vn index from the global range.
     431     3226921 :     BOOST_FOREACH(const ExtCommunity::ExtCommunityValue &comm,
     432             :                   ext_community->communities()) {
     433     1534605 :         if (!ExtCommunity::is_origin_vn(comm))
     434     1518114 :             continue;
     435       18464 :         OriginVn origin_vn(comm);
     436       36930 :         if (!origin_vn.IsGlobal() &&
     437       18465 :             origin_vn.as_number() != server->autonomous_system()) {
     438        2028 :             continue;
     439             :         }
     440       16437 :         return ExtCommunityPtr(ext_community);
     441             :     }
     442             : 
     443             :     // Add the OriginVn if we have a valid vn index.
     444             :     int vn_index =
     445      174289 :         server->routing_instance_mgr()->GetVnIndexByExtCommunity(ext_community);
     446      174479 :     return UpdateOriginVn(server, ext_community, vn_index);
     447      515114 : }
     448             : 
     449             : //
     450             : // Concurrency: Called in the context of the DB partition task.
     451             : //
     452             : // This function handles
     453             : //   1. Table Notification for path replication
     454             : //   2. Table walk for import/export of new targets
     455             : //
     456             : // Replicate a path (clone the BgpPath) to secondary BgpTables based on the
     457             : // export targets of the primary BgpTable.
     458             : // If primary table is a VRF table attach it's export targets to replicated
     459             : // path in the VPN table.
     460             : //
     461     1992250 : bool RoutePathReplicator::RouteListener(TableState *ts,
     462             :     DBTablePartBase *root, DBEntryBase *entry) {
     463     1992250 :     CHECK_CONCURRENCY("db::DBTable");
     464             : 
     465     1991347 :     BgpTable *table = static_cast<BgpTable *>(root->parent());
     466     1991303 :     BgpRoute *rt = static_cast<BgpRoute *>(entry);
     467     1991303 :     const RoutingInstance *rtinstance = table->routing_instance();
     468             : 
     469     1991335 :     DBTableBase::ListenerId id = ts->listener_id();
     470     1991332 :     assert(id != DBTableBase::kInvalidId);
     471             : 
     472             :     // Get the DBState.
     473             :     RtReplicated *dbstate =
     474     1991332 :         static_cast<RtReplicated *>(rt->GetState(table, id));
     475     1993871 :     RtReplicated::ReplicatedRtPathList replicated_path_list;
     476             : 
     477             :     //Flag to track if any change happenned to route in last 30 minutes
     478     1992875 :     bool route_unchanged = false;
     479             :     //List of tables that needs replication of route
     480     1992875 :     RtGroup::RtGroupMemberList addedTables;
     481             :     //List of tables that doesn't need replication of route
     482     1991850 :     RtGroup::RtGroupMemberList deletedTables;
     483             :     //List of tables having the latest changes in route
     484     1991277 :     RtGroup::RtGroupMemberList previousTables;
     485             :     //Threshold used for optimised replication
     486     1991017 :     uint64_t optimizationThresholdTime = 30ULL * 60 * 1000000;
     487     1991017 :     uint64_t start = UTCTimestampUsec();
     488             : 
     489             :     //Optimize only if last route change occurred 30 mins before.
     490             :     //We update the route_unchanged flag to true
     491     1993736 :     if ( (start - rt->last_update_at() > optimizationThresholdTime) &&
     492             :           dbstate != NULL)
     493             :     {
     494         135 :         RPR_TRACE(RouteListener, "Route change occurred before threshold \
     495             :         time, optimising replication");
     496         135 :         route_unchanged = true;
     497             :     }
     498             : 
     499             :     //
     500             :     // Cleanup if the route is not usable.
     501             :     // If route aggregation is enabled, contributing route/more specific route
     502             :     // for a aggregate route will NOT be replicated to destination table
     503             :     //
     504     2456603 :     if (!rt->IsUsable() || (table->IsRouteAggregationSupported() &&
     505      463138 :                             !rtinstance->deleted() &&
     506      460265 :                             table->IsContributingRoute(rt))) {
     507      717421 :         if (!dbstate) {
     508      562085 :             return true;
     509             :         }
     510      155336 :         DBStateSync(table, ts, rt, dbstate, &replicated_path_list);
     511      155524 :         return true;
     512             :     }
     513             : 
     514             :     // Create and set new DBState on the route.  This will get cleaned up via
     515             :     // via the call to DBStateSync if we don't need to replicate the route to
     516             :     // any tables.
     517     1275303 :     if (dbstate == NULL) {
     518     1044911 :         dbstate = new RtReplicated(this);
     519     1044860 :         rt->SetState(table, id, dbstate);
     520             :     }
     521             : 
     522             :     // Get the export route target list from the routing instance.
     523     1275850 :     ExtCommunity::ExtCommunityList export_list;
     524     1275602 :     if (!rtinstance->IsMasterRoutingInstance()) {
     525     5806823 :         BOOST_FOREACH(RouteTarget rtarget, rtinstance->GetExportList()) {
     526     2495779 :             export_list.push_back(rtarget.GetExtCommunity());
     527             :         }
     528             :     }
     529             : 
     530             :     // Updating previousTables with the list of tables having the information
     531             :     // about the route.
     532     1275312 :     if (route_unchanged){
     533         135 :         replicated_path_list = dbstate->GetList();
     534         423 :         BOOST_FOREACH (RtReplicated::SecondaryRouteInfo path,
     535             :                        replicated_path_list){
     536         144 :             previousTables.insert(path.table_);
     537             :         }
     538             :     }
     539             : 
     540             :     // Replicate all feasible and non-replicated paths.
     541     1275312 :     for (Route::PathList::iterator it = rt->GetPathList().begin();
     542     6079189 :         it != rt->GetPathList().end(); ++it) {
     543     1770234 :         BgpPath *path = static_cast<BgpPath *>(it.operator->());
     544             : 
     545             :         // Skip if the source peer is down.
     546     2611107 :         if (!path->IsStale() && !path->IsLlgrStale() && path->GetPeer() &&
     547      840637 :             !path->GetPeer()->IsReady())
     548     1280211 :             continue;
     549             : 
     550             :         // No need to replicate aliased or replicated paths.
     551     1666269 :         if (path->IsReplicated() || path->IsAliased())
     552     1145204 :             continue;
     553             : 
     554             :         // Do not replicate non-ecmp paths.
     555      521027 :         if (rt->BestPath()->PathCompare(*path, true))
     556        6228 :             break;
     557             : 
     558             :         // Do not replicate if nexthop is not hitched by ermvpn tree.
     559      514759 :         if (path->CheckErmVpn())
     560           0 :             break;
     561             : 
     562      514758 :         const BgpAttr *attr = path->GetAttr();
     563      514754 :         const ExtCommunity *ext_community = attr->ext_community();
     564             : 
     565             :         ExtCommunityPtr extcomm_ptr =
     566      514750 :           UpdateExtCommunity(server(), rtinstance, ext_community, export_list);
     567      515114 :         ext_community = extcomm_ptr.get();
     568      515113 :         if (!ext_community)
     569        1053 :             continue;
     570             : 
     571             :         // Go through all extended communities.
     572             :         //
     573             :         // Get the vn_index from the OriginVn extended community.
     574             :         // For each RouteTarget extended community, get the list of tables
     575             :         // to which we need to replicate the path.
     576      514060 :         int vn_index = 0;
     577      514060 :         RtGroup::RtGroupMemberList secondary_tables;
     578     5810922 :         BOOST_FOREACH(const ExtCommunity::ExtCommunityValue &comm,
     579             :                       ext_community->communities()) {
     580     2648411 :             if (ExtCommunity::is_origin_vn(comm)) {
     581       79546 :                 OriginVn origin_vn(comm);
     582       79546 :                 vn_index = origin_vn.vn_index();
     583     2568823 :             } else if (ExtCommunity::is_route_target(comm)) {
     584             :                 RtGroup *group =
     585     2115866 :                     server()->rtarget_group_mgr()->GetRtGroup(comm);
     586     2116228 :                 if (!group)
     587      579844 :                     continue;
     588             :                 RtGroup::RtGroupMemberList import_list =
     589     2114153 :                     group->GetImportTables(family());
     590     2113915 :                 if (import_list.empty())
     591      577769 :                     continue;
     592     1536135 :                 secondary_tables.insert(import_list.begin(), import_list.end());
     593     2113716 :             }
     594             :         }
     595             : 
     596             :         // Update with family specific secondary tables.
     597      514019 :         table->UpdateSecondaryTablesForReplication(rt, &secondary_tables);
     598             : 
     599             :         // Skip if we don't need to replicate the path to any tables.
     600      514019 :         if (secondary_tables.empty())
     601       29794 :             continue;
     602             : 
     603             :         // Add OriginVn when replicating self-originated routes from a VRF.
     604      404926 :         if (!vn_index && !rtinstance->IsMasterRoutingInstance() &&
     605      889146 :             path->IsVrfOriginated() && rtinstance->virtual_network_index()) {
     606       47555 :             vn_index = rtinstance->virtual_network_index();
     607       47555 :             extcomm_ptr = UpdateOriginVn(server_, extcomm_ptr.get(), vn_index);
     608             :         }
     609             : 
     610      484223 :         if (route_unchanged){
     611         137 :             addedTables = RtGroup::RtGroupMemberList();
     612             :             // Finding the difference between sets, secondary_tables and
     613             :             // previousTables
     614         137 :             std::set_difference(secondary_tables.begin(), secondary_tables.end(),
     615             :                                 previousTables.begin(), previousTables.end(),
     616             :                                 std::inserter(addedTables, addedTables.end()));
     617         137 :             std::set_difference(previousTables.begin(), previousTables.end(),
     618             :                                 secondary_tables.begin(), secondary_tables.end(),
     619             :                                 std::inserter(deletedTables, deletedTables.end()));
     620         449 :             BOOST_FOREACH (RtReplicated::SecondaryRouteInfo path,
     621             :                        dbstate->GetList()){
     622         156 :                 if (deletedTables.find(path.table_)!=deletedTables.end()) {
     623           1 :                     replicated_path_list.erase(path);
     624             :                 }
     625             :             }
     626             :             //Updating the secondary tables with the difference.
     627         137 :             secondary_tables = addedTables;
     628             : 
     629             :         }
     630             : 
     631             : 
     632             :         // Replicate path to all destination tables.
     633     3702938 :         BOOST_FOREACH(BgpTable *dest, secondary_tables) {
     634             :             // Skip if destination is same as source table.
     635     1609283 :             if (dest == table)
     636      665449 :                 continue;
     637             : 
     638     1125177 :             const RoutingInstance *dest_rtinstance = dest->routing_instance();
     639     1125185 :             ExtCommunityPtr new_extcomm_ptr = extcomm_ptr;
     640             : 
     641             :             // If the origin vn is unresolved, see if route has a RouteTarget
     642             :             // that's in the set of export RouteTargets for the dest instance.
     643             :             // If so, we set the origin vn for the replicated route to be the
     644             :             // vn for the dest instance.
     645     1125899 :             if (!vn_index && dest_rtinstance->virtual_network_index() &&
     646         468 :                 dest_rtinstance->HasExportTarget(ext_community)) {
     647         368 :                 int dest_vn_index = dest_rtinstance->virtual_network_index();
     648         736 :                 new_extcomm_ptr = UpdateOriginVn(server_, extcomm_ptr.get(),
     649         368 :                                                  dest_vn_index);
     650             :             }
     651             : 
     652             :             // Replicate the route to the destination table.  The destination
     653             :             // table may decide to not replicate based on it's own policy e.g.
     654             :             // multicast routes are never leaked across routing-instances.
     655     1125416 :             BgpRoute *replicated_rt = dest->RouteReplicate(
     656             :                 server_, table, rt, path, new_extcomm_ptr);
     657     1125435 :             if (!replicated_rt)
     658      181353 :                 continue;
     659             : 
     660             :             // Add information about the secondary path to the replicated path
     661             :             // list.
     662      944065 :             RtReplicated::SecondaryRouteInfo rtinfo(dest, path->GetPeer(),
     663     1888141 :                 path->GetPathId(), path->GetSource(), replicated_rt);
     664      944056 :             pair<RtReplicated::ReplicatedRtPathList::iterator, bool> result;
     665      944040 :             result = replicated_path_list.insert(rtinfo);
     666             :             // Assert if the insertion to replication path list fails
     667      944046 :             if (!route_unchanged)
     668      944045 :                 assert(result.second);
     669      944046 :             RPR_TRACE_ONLY(Replicate, table->name(), rt->ToString(),
     670             :                            path->ToString(),
     671             :                            BgpPath::PathIdString(path->GetPathId()),
     672             :                            dest->name(), replicated_rt->ToString());
     673     1125425 :         }
     674      544908 :     }
     675             : 
     676             :     // Update the DBState to reflect the new list of secondary paths. The
     677             :     // DBState will get cleared if the list is empty.
     678     1275274 :     DBStateSync(table, ts, rt, dbstate, &replicated_path_list);
     679     1275936 :     return true;
     680     1993545 : }
     681         173 : const RtReplicated *RoutePathReplicator::GetReplicationState(
     682             :         BgpTable *table, BgpRoute *rt) const {
     683         173 :     const TableState *ts = FindTableState(table);
     684         173 :     if (!ts)
     685           0 :         return NULL;
     686             :     RtReplicated *dbstate =
     687         173 :         static_cast<RtReplicated *>(rt->GetState(table, ts->listener_id()));
     688         173 :     return dbstate;
     689             : }
     690             : 
     691             : //
     692             : // Return the list of secondary table names for the given primary path.
     693             : //
     694        5467 : vector<string> RoutePathReplicator::GetReplicatedTableNameList(
     695             :     const BgpTable *table, const BgpRoute *rt, const BgpPath *path) const {
     696        5467 :     const TableState *ts = FindTableState(table);
     697        5457 :     if (!ts)
     698        5155 :         return vector<string>();
     699             :     const RtReplicated *dbstate = static_cast<const RtReplicated *>(
     700         302 :         rt->GetState(table, ts->listener_id()));
     701         302 :     if (!dbstate)
     702          21 :         return vector<string>();
     703         281 :     return dbstate->GetTableNameList(path);
     704             : }
     705             : 
     706      516474 : void RoutePathReplicator::DeleteSecondaryPath(BgpTable *table, BgpRoute *rt,
     707             :     const RtReplicated::SecondaryRouteInfo &rtinfo) {
     708      516474 :     BgpRoute *rt_secondary = rtinfo.rt_;
     709      516474 :     BgpTable *secondary_table = rtinfo.table_;
     710      516474 :     const IPeer *peer = rtinfo.peer_;
     711      516474 :     uint32_t path_id = rtinfo.path_id_;
     712      516474 :     BgpPath::PathSource src = rtinfo.src_;
     713             : 
     714             :     DBTablePartBase *partition =
     715      516474 :         secondary_table->GetTablePartition(rt_secondary);
     716      516294 :     BgpPath *secondary_path = rt_secondary->FindSecondaryPath(rt, src,
     717             :                                                               peer, path_id);
     718      516844 :     if (secondary_path && secondary_path->NeedsResolution()) {
     719           0 :        secondary_table->path_resolver()->StopPathResolution(partition->index(),
     720             :                                                        secondary_path);
     721             :     }
     722      516813 :     assert(rt_secondary->RemoveSecondaryPath(rt, src, peer, path_id));
     723      517424 :     if (rt_secondary->count() == 0) {
     724      493250 :         RPR_TRACE_ONLY(Flush, secondary_table->name(), rt_secondary->ToString(),
     725             :                        peer ? peer->ToString() : "Nil",
     726             :                        BgpPath::PathIdString(path_id), table->name(),
     727             :                        rt->ToString(), "Delete");
     728      493434 :         partition->Delete(rt_secondary);
     729             :     } else {
     730       23803 :         partition->Notify(rt_secondary);
     731       23831 :         RPR_TRACE_ONLY(Flush, secondary_table->name(), rt_secondary->ToString(),
     732             :                        peer ? peer->ToString() : "Nil",
     733             :                        BgpPath::PathIdString(path_id), table->name(),
     734             :                        rt->ToString(), "Path update");
     735             :     }
     736      517175 : }
     737             : 
     738           0 : string RtReplicated::SecondaryRouteInfo::ToString() const {
     739           0 :     ostringstream out;
     740           0 :     out << table_->name() << "(" << table_ << ")" << ":" <<
     741           0 :         peer_->ToString() << "(" << peer_ << ")" << ":" <<
     742           0 :         rt_->ToString() << "(" << rt_ << ")";
     743           0 :     return out.str();
     744           0 : }

Generated by: LCOV version 1.14