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-18 01:51:13 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      254208 :     explicit DeleteActor(TableState *ts)
      53      254208 :         : LifetimeActor(ts->replicator()->server()->lifetime_manager()),
      54      254208 :           ts_(ts) {
      55      254210 :     }
      56             : 
      57      254297 :     virtual bool MayDelete() const {
      58      254297 :         return ts_->MayDelete();
      59             :     }
      60             : 
      61      254210 :     virtual void Shutdown() {
      62      254210 :     }
      63             : 
      64      254210 :     virtual void Destroy() {
      65      254210 :         ts_->replicator()->DeleteTableState(ts_->table());
      66      254210 :     }
      67             : 
      68             : private:
      69             :     TableState *ts_;
      70             : };
      71             : 
      72      254208 : TableState::TableState(RoutePathReplicator *replicator, BgpTable *table)
      73      254208 :     : replicator_(replicator),
      74      254208 :       table_(table),
      75      254208 :       listener_id_(DBTableBase::kInvalidId),
      76      254208 :       deleter_(new DeleteActor(this)),
      77      254208 :       table_delete_ref_(this, table->deleter()) {
      78      254207 :     assert(table->deleter() != NULL);
      79      254207 : }
      80             : 
      81      254210 : TableState::~TableState() {
      82      254210 :     if (walk_ref() != NULL) {
      83       22599 :         table()->ReleaseWalker(walk_ref());
      84             :     }
      85      254210 : }
      86             : 
      87      254210 : void TableState::ManagedDelete() {
      88      254210 :     deleter()->Delete();
      89      254210 : }
      90             : 
      91           0 : bool TableState::deleted() const {
      92           0 :     return deleter()->IsDeleted();
      93             : }
      94             : 
      95      905587 : LifetimeActor *TableState::deleter() {
      96      905587 :     return deleter_.get();
      97             : }
      98             : 
      99           0 : const LifetimeActor *TableState::deleter() const {
     100           0 :     return deleter_.get();
     101             : }
     102             : 
     103      254297 : bool TableState::MayDelete() const {
     104      531212 :     if (list_.empty() && !route_count() &&
     105      276915 :         ((walk_ref() == NULL) || !walk_ref()->walk_is_active()))
     106      254210 :         return true;
     107          87 :     return false;
     108             : }
     109             : 
     110      632302 : void TableState::RetryDelete() {
     111      632302 :     if (!deleter()->IsDeleted())
     112      613199 :         return;
     113       19077 :     deleter()->RetryDelete();
     114             : }
     115             : 
     116      668401 : void TableState::AddGroup(RtGroup *group) {
     117      668401 :     list_.insert(group);
     118      668542 : }
     119             : 
     120      668564 : void TableState::RemoveGroup(RtGroup *group) {
     121      668564 :     list_.erase(group);
     122      668565 : }
     123             : 
     124      429662 : const RtGroup *TableState::FindGroup(RtGroup *group) const {
     125      429662 :     GroupList::const_iterator it = list_.find(group);
     126      429631 :     return (it != list_.end() ? *it : NULL);
     127             : }
     128             : 
     129      254308 : uint32_t TableState::route_count() const {
     130      254308 :     return table_->GetDBStateCount(listener_id());
     131             : }
     132             : 
     133     1036094 : RtReplicated::RtReplicated(RoutePathReplicator *replicator)
     134     1036094 :     : replicator_(replicator) {
     135     1036039 : }
     136             : 
     137      517464 : void RtReplicated::AddRouteInfo(BgpTable *table, BgpRoute *rt,
     138             :     ReplicatedRtPathList::const_iterator it) {
     139      517464 :     pair<ReplicatedRtPathList::iterator, bool> result;
     140      517464 :     result = replicate_list_.insert(*it);
     141      517483 :     assert(result.second);
     142      517483 : }
     143             : 
     144      517101 : void RtReplicated::DeleteRouteInfo(BgpTable *table, BgpRoute *rt,
     145             :     ReplicatedRtPathList::const_iterator it) {
     146      517101 :     replicator_->DeleteSecondaryPath(table, rt, *it);
     147      517406 :     replicate_list_.erase(it);
     148      517418 : }
     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      709684 : TableState *RoutePathReplicator::AddTableState(BgpTable *table,
     193             :     RtGroup *group) {
     194      709684 :     assert(table->IsVpnTable() || group);
     195             : 
     196      709663 :     TableStateList::iterator loc = table_state_list_.find(table);
     197      709463 :     if (loc == table_state_list_.end()) {
     198      254208 :         TableState *ts = new TableState(this, table);
     199      254207 :         DBTableBase::ListenerId id = table->Register(
     200             :             boost::bind(&RoutePathReplicator::RouteListener, this, ts, _1, _2),
     201             :             "RoutePathReplicator");
     202      254182 :         ts->set_listener_id(id);
     203      254185 :         if (group)
     204      213050 :             ts->AddGroup(group);
     205      254206 :         table_state_list_.insert(make_pair(table, ts));
     206      254207 :         RPR_TRACE(RegTable, table->name());
     207      254204 :         return ts;
     208             :     } else {
     209      455365 :         assert(group);
     210      455365 :         TableState *ts = loc->second;
     211      455368 :         ts->AddGroup(group);
     212      455484 :         return ts;
     213             :     }
     214             : }
     215             : 
     216      668565 : void RoutePathReplicator::RemoveTableState(BgpTable *table, RtGroup *group) {
     217      668565 :     TableState *ts = FindTableState(table);
     218      668564 :     assert(ts);
     219      668564 :     ts->RemoveGroup(group);
     220      668565 : }
     221             : 
     222      254210 : void RoutePathReplicator::DeleteTableState(BgpTable *table) {
     223      254210 :     TableState *ts = FindTableState(table);
     224      254210 :     assert(ts);
     225      254210 :     RPR_TRACE(UnregTable, table->name());
     226      254210 :     table->Unregister(ts->listener_id());
     227      254210 :     table_state_list_.erase(table);
     228      254210 :     delete ts;
     229      254210 : }
     230             : 
     231     1858864 : TableState *RoutePathReplicator::FindTableState(BgpTable *table) {
     232     1858864 :     TableStateList::iterator loc = table_state_list_.find(table);
     233     1858825 :     return (loc != table_state_list_.end() ? loc->second : NULL);
     234             : }
     235             : 
     236        5646 : const TableState *RoutePathReplicator::FindTableState(
     237             :     const BgpTable *table) const {
     238             :     TableStateList::const_iterator loc =
     239        5646 :         table_state_list_.find(const_cast<BgpTable *>(table));
     240        5639 :     return (loc != table_state_list_.end() ? loc->second : NULL);
     241             : }
     242             : 
     243             : void
     244       51364 : RoutePathReplicator::RequestWalk(BgpTable *table) {
     245       51364 :     CHECK_CONCURRENCY("bgp::Config", "bgp::ConfigHelper");
     246       51364 :     TableState *ts = FindTableState(table);
     247       51364 :     assert(ts);
     248       51364 :     if (!ts->walk_ref()) {
     249             :         DBTable::DBTableWalkRef walk_ref = table->AllocWalker(
     250             :           boost::bind(&RoutePathReplicator::RouteListener, this, ts, _1, _2),
     251       45198 :           boost::bind(&RoutePathReplicator::BulkReplicationDone, this, _2));
     252       22599 :         table->WalkTable(walk_ref);
     253       22599 :         ts->set_walk_ref(walk_ref);
     254       22599 :     } else {
     255       28765 :         table->WalkAgain(ts->walk_ref());
     256             :     }
     257       51364 : }
     258             : 
     259             : void
     260       24600 : RoutePathReplicator::BulkReplicationDone(DBTableBase *dbtable) {
     261       24600 :     CHECK_CONCURRENCY("db::Walker");
     262       24600 :     BgpTable *table = static_cast<BgpTable *>(dbtable);
     263       24600 :     RPR_TRACE(WalkDone, table->name());
     264       24600 :     TableState *ts = FindTableState(table);
     265       24600 :     ts->RetryDelete();
     266       24600 : }
     267             : 
     268      430053 : void RoutePathReplicator::JoinVpnTable(RtGroup *group) {
     269      430053 :     CHECK_CONCURRENCY("bgp::Config", "bgp::ConfigHelper");
     270      430087 :     TableState *vpn_ts = FindTableState(vpn_table_);
     271      430030 :     if (!vpn_ts || vpn_ts->FindGroup(group))
     272         370 :         return;
     273      429620 :     RPR_TRACE(TableJoin, vpn_table_->name(), group->rt().ToString(), true);
     274      429746 :     group->AddImportTable(family(), vpn_table_);
     275      429838 :     RPR_TRACE(TableJoin, vpn_table_->name(), group->rt().ToString(), false);
     276      429834 :     group->AddExportTable(family(), vpn_table_);
     277      429831 :     AddTableState(vpn_table_, group);
     278             : }
     279             : 
     280      430024 : void RoutePathReplicator::LeaveVpnTable(RtGroup *group) {
     281      430024 :     CHECK_CONCURRENCY("bgp::Config", "bgp::ConfigHelper");
     282      430025 :     TableState *vpn_ts = FindTableState(vpn_table_);
     283      430025 :     if (!vpn_ts)
     284         185 :         return;
     285      429840 :     RPR_TRACE(TableLeave, vpn_table_->name(), group->rt().ToString(), true);
     286      429840 :     group->RemoveImportTable(family(), vpn_table_);
     287      429840 :     RPR_TRACE(TableLeave, vpn_table_->name(), group->rt().ToString(), false);
     288      429840 :     group->RemoveExportTable(family(), vpn_table_);
     289      429840 :     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      928138 : void RoutePathReplicator::Join(BgpTable *table, const RouteTarget &rt,
     298             :                                bool import) {
     299      928138 :     CHECK_CONCURRENCY("bgp::Config", "bgp::ConfigHelper");
     300             : 
     301      928035 :     std::scoped_lock lock(mutex_);
     302      928655 :     RPR_TRACE(TableJoin, table->name(), rt.ToString(), import);
     303             : 
     304      928669 :     bool first = false;
     305      928669 :     RtGroup *group = server()->rtarget_group_mgr()->LocateRtGroup(rt);
     306      928786 :     if (import) {
     307      690061 :         first = group->AddImportTable(family(), table);
     308      690057 :         if (group->HasDepRoutes())
     309         200 :             server()->rtarget_group_mgr()->NotifyRtGroup(rt);
     310      689996 :         if (family_ == Address::INETVPN)
     311      138011 :             server_->NotifyAllStaticRoutes();
     312     1338587 :         BOOST_FOREACH(BgpTable *sec_table, group->GetExportTables(family())) {
     313      324290 :             if (sec_table->IsVpnTable() || sec_table->empty())
     314      323063 :                 continue;
     315        1223 :             RequestWalk(sec_table);
     316             :         }
     317             :     } else {
     318      238725 :         first = group->AddExportTable(family(), table);
     319      238725 :         AddTableState(table, group);
     320      238719 :         if (!table->empty()) {
     321          60 :             RequestWalk(table);
     322             :         }
     323             :     }
     324             : 
     325             :     // Join the vpn table when group is created.
     326      928437 :     if (first)
     327      430055 :         JoinVpnTable(group);
     328      928577 : }
     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      928790 : void RoutePathReplicator::Leave(BgpTable *table, const RouteTarget &rt,
     336             :                                 bool import) {
     337      928790 :     CHECK_CONCURRENCY("bgp::Config", "bgp::ConfigHelper");
     338             : 
     339      928789 :     std::scoped_lock lock(mutex_);
     340      928789 :     RtGroup *group = server()->rtarget_group_mgr()->GetRtGroup(rt);
     341      928790 :     assert(group);
     342      928790 :     RPR_TRACE(TableLeave, table->name(), rt.ToString(), import);
     343             : 
     344      928790 :     if (import) {
     345      690065 :         group->RemoveImportTable(family(), table);
     346      690063 :         if (group->HasDepRoutes())
     347      132410 :             server()->rtarget_group_mgr()->NotifyRtGroup(rt);
     348      690063 :         if (family_ == Address::INETVPN)
     349      138013 :             server_->NotifyAllStaticRoutes();
     350     2674789 :         BOOST_FOREACH(BgpTable *sec_table, group->GetExportTables(family())) {
     351      992360 :             if (sec_table->IsVpnTable() || sec_table->empty())
     352      965459 :                 continue;
     353       26899 :             RequestWalk(sec_table);
     354             :         }
     355             :     } else {
     356      238725 :         group->RemoveExportTable(family(), table);
     357      238725 :         RemoveTableState(table, group);
     358      238725 :         if (!table->empty()) {
     359       23162 :             RequestWalk(table);
     360             :         }
     361             :     }
     362             : 
     363             :     // Leave the vpn table when the last VRF has left the group.
     364      928784 :     if (!group->HasVrfTables(family())) {
     365      430024 :         LeaveVpnTable(group);
     366      430025 :         server()->rtarget_group_mgr()->RemoveRtGroup(rt);
     367             :     }
     368      928784 : }
     369             : 
     370     1423143 : void RoutePathReplicator::DBStateSync(BgpTable *table, TableState *ts,
     371             :     BgpRoute *rt, RtReplicated *dbstate,
     372             :     const RtReplicated::ReplicatedRtPathList *future) {
     373     1423143 :     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     1422970 :     if (dbstate->GetList().empty()) {
     378     1036216 :         rt->ClearState(table, ts->listener_id());
     379     1036439 :         delete dbstate;
     380     1036304 :         if (table->GetDBStateCount(ts->listener_id()) == 0)
     381      607706 :             ts->RetryDelete();
     382             :     }
     383     1423226 : }
     384             : 
     385      223100 : static ExtCommunityPtr UpdateOriginVn(BgpServer *server,
     386             :                                       const ExtCommunity *ext_community,
     387             :                                       int vn_index) {
     388      223100 :     as_t asn = server->autonomous_system();
     389      223094 :     ExtCommunityPtr extcomm_ptr;
     390      223094 :     if (vn_index) {
     391       53926 :         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       53926 :             OriginVn origin_vn(asn, vn_index);
     400      161785 :             extcomm_ptr = server->extcomm_db()->ReplaceOriginVnAndLocate(
     401      107859 :                 ext_community, origin_vn.GetExtCommunity());
     402       53931 :             return extcomm_ptr;
     403             :         }
     404             :     }
     405      169168 :     extcomm_ptr = server->extcomm_db()->RemoveOriginVnAndLocate(ext_community);
     406      169204 :     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      516240 : 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      516240 :     ExtCommunityPtr extcomm_ptr;
     419      516240 :     if (!rtinstance->IsMasterRoutingInstance()) {
     420             :         extcomm_ptr =
     421      323413 :             server->extcomm_db()->AppendAndLocate(ext_community, export_list);
     422      323447 :         return extcomm_ptr;
     423             :     }
     424             : 
     425             :     // Bail if we have a vpn route without extended communities.
     426      192825 :     if (!ext_community)
     427        1051 :         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     3269419 :     BOOST_FOREACH(const ExtCommunity::ExtCommunityValue &comm,
     432             :                   ext_community->communities()) {
     433     1555417 :         if (!ExtCommunity::is_origin_vn(comm))
     434     1538815 :             continue;
     435       18513 :         OriginVn origin_vn(comm);
     436       37028 :         if (!origin_vn.IsGlobal() &&
     437       18514 :             origin_vn.as_number() != server->autonomous_system()) {
     438        1925 :             continue;
     439             :         }
     440       16589 :         return ExtCommunityPtr(ext_community);
     441             :     }
     442             : 
     443             :     // Add the OriginVn if we have a valid vn index.
     444             :     int vn_index =
     445      175199 :         server->routing_instance_mgr()->GetVnIndexByExtCommunity(ext_community);
     446      175299 :     return UpdateOriginVn(server, ext_community, vn_index);
     447      516416 : }
     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     1983820 : bool RoutePathReplicator::RouteListener(TableState *ts,
     462             :     DBTablePartBase *root, DBEntryBase *entry) {
     463     1983820 :     CHECK_CONCURRENCY("db::DBTable");
     464             : 
     465     1983357 :     BgpTable *table = static_cast<BgpTable *>(root->parent());
     466     1983337 :     BgpRoute *rt = static_cast<BgpRoute *>(entry);
     467     1983337 :     const RoutingInstance *rtinstance = table->routing_instance();
     468             : 
     469     1983338 :     DBTableBase::ListenerId id = ts->listener_id();
     470     1983262 :     assert(id != DBTableBase::kInvalidId);
     471             : 
     472             :     // Get the DBState.
     473             :     RtReplicated *dbstate =
     474     1983262 :         static_cast<RtReplicated *>(rt->GetState(table, id));
     475     1984623 :     RtReplicated::ReplicatedRtPathList replicated_path_list;
     476             : 
     477             :     //Flag to track if any change happenned to route in last 30 minutes
     478     1984320 :     bool route_unchanged = false;
     479             :     //List of tables that needs replication of route
     480     1984320 :     RtGroup::RtGroupMemberList addedTables;
     481             :     //List of tables that doesn't need replication of route
     482     1983816 :     RtGroup::RtGroupMemberList deletedTables;
     483             :     //List of tables having the latest changes in route
     484     1983501 :     RtGroup::RtGroupMemberList previousTables;
     485             :     //Threshold used for optimised replication
     486     1983356 :     uint64_t optimizationThresholdTime = 30ULL * 60 * 1000000;
     487     1983356 :     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     1984565 :     if ( (start - rt->last_update_at() > optimizationThresholdTime) &&
     492             :           dbstate != NULL)
     493             :     {
     494         115 :         RPR_TRACE(RouteListener, "Route change occurred before threshold \
     495             :         time, optimising replication");
     496         115 :         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     2447425 :     if (!rt->IsUsable() || (table->IsRouteAggregationSupported() &&
     505      462989 :                             !rtinstance->deleted() &&
     506      459934 :                             table->IsContributingRoute(rt))) {
     507      717452 :         if (!dbstate) {
     508      561299 :             return true;
     509             :         }
     510      156153 :         DBStateSync(table, ts, rt, dbstate, &replicated_path_list);
     511      156224 :         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     1266621 :     if (dbstate == NULL) {
     518     1036095 :         dbstate = new RtReplicated(this);
     519     1036037 :         rt->SetState(table, id, dbstate);
     520             :     }
     521             : 
     522             :     // Get the export route target list from the routing instance.
     523     1266895 :     ExtCommunity::ExtCommunityList export_list;
     524     1266811 :     if (!rtinstance->IsMasterRoutingInstance()) {
     525     5804420 :         BOOST_FOREACH(RouteTarget rtarget, rtinstance->GetExportList()) {
     526     2494466 :             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     1266645 :     if (route_unchanged){
     533         115 :         replicated_path_list = dbstate->GetList();
     534         363 :         BOOST_FOREACH (RtReplicated::SecondaryRouteInfo path,
     535             :                        replicated_path_list){
     536         124 :             previousTables.insert(path.table_);
     537             :         }
     538             :     }
     539             : 
     540             :     // Replicate all feasible and non-replicated paths.
     541     1266645 :     for (Route::PathList::iterator it = rt->GetPathList().begin();
     542     6044265 :         it != rt->GetPathList().end(); ++it) {
     543     1761459 :         BgpPath *path = static_cast<BgpPath *>(it.operator->());
     544             : 
     545             :         // Skip if the source peer is down.
     546     2594270 :         if (!path->IsStale() && !path->IsLlgrStale() && path->GetPeer() &&
     547      832553 :             !path->GetPeer()->IsReady())
     548     1270056 :             continue;
     549             : 
     550             :         // No need to replicate aliased or replicated paths.
     551     1667900 :         if (path->IsReplicated() || path->IsAliased())
     552     1145448 :             continue;
     553             : 
     554             :         // Do not replicate non-ecmp paths.
     555      522419 :         if (rt->BestPath()->PathCompare(*path, true))
     556        6151 :             break;
     557             : 
     558             :         // Do not replicate if nexthop is not hitched by ermvpn tree.
     559      516245 :         if (path->CheckErmVpn())
     560           0 :             break;
     561             : 
     562      516244 :         const BgpAttr *attr = path->GetAttr();
     563      516242 :         const ExtCommunity *ext_community = attr->ext_community();
     564             : 
     565             :         ExtCommunityPtr extcomm_ptr =
     566      516240 :           UpdateExtCommunity(server(), rtinstance, ext_community, export_list);
     567      516409 :         ext_community = extcomm_ptr.get();
     568      516417 :         if (!ext_community)
     569        1051 :             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      515366 :         int vn_index = 0;
     577      515366 :         RtGroup::RtGroupMemberList secondary_tables;
     578     5853439 :         BOOST_FOREACH(const ExtCommunity::ExtCommunityValue &comm,
     579             :                       ext_community->communities()) {
     580     2668941 :             if (ExtCommunity::is_origin_vn(comm)) {
     581       79573 :                 OriginVn origin_vn(comm);
     582       79573 :                 vn_index = origin_vn.vn_index();
     583     2589408 :             } else if (ExtCommunity::is_route_target(comm)) {
     584             :                 RtGroup *group =
     585     2134187 :                     server()->rtarget_group_mgr()->GetRtGroup(comm);
     586     2134494 :                 if (!group)
     587      593911 :                     continue;
     588             :                 RtGroup::RtGroupMemberList import_list =
     589     2132510 :                     group->GetImportTables(family());
     590     2132275 :                 if (import_list.empty())
     591      591927 :                     continue;
     592     1540347 :                 secondary_tables.insert(import_list.begin(), import_list.end());
     593     2132146 :             }
     594             :         }
     595             : 
     596             :         // Update with family specific secondary tables.
     597      515340 :         table->UpdateSecondaryTablesForReplication(rt, &secondary_tables);
     598             : 
     599             :         // Skip if we don't need to replicate the path to any tables.
     600      515340 :         if (secondary_tables.empty())
     601       29777 :             continue;
     602             : 
     603             :         // Add OriginVn when replicating self-originated routes from a VRF.
     604      406221 :         if (!vn_index && !rtinstance->IsMasterRoutingInstance() &&
     605      891784 :             path->IsVrfOriginated() && rtinstance->virtual_network_index()) {
     606       47435 :             vn_index = rtinstance->virtual_network_index();
     607       47435 :             extcomm_ptr = UpdateOriginVn(server_, extcomm_ptr.get(), vn_index);
     608             :         }
     609             : 
     610      485565 :         if (route_unchanged){
     611         117 :             addedTables = RtGroup::RtGroupMemberList();
     612             :             // Finding the difference between sets, secondary_tables and
     613             :             // previousTables
     614         117 :             std::set_difference(secondary_tables.begin(), secondary_tables.end(),
     615             :                                 previousTables.begin(), previousTables.end(),
     616             :                                 std::inserter(addedTables, addedTables.end()));
     617         117 :             std::set_difference(previousTables.begin(), previousTables.end(),
     618             :                                 secondary_tables.begin(), secondary_tables.end(),
     619             :                                 std::inserter(deletedTables, deletedTables.end()));
     620         389 :             BOOST_FOREACH (RtReplicated::SecondaryRouteInfo path,
     621             :                        dbstate->GetList()){
     622         136 :                 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         117 :             secondary_tables = addedTables;
     628             : 
     629             :         }
     630             : 
     631             : 
     632             :         // Replicate path to all destination tables.
     633     3714947 :         BOOST_FOREACH(BgpTable *dest, secondary_tables) {
     634             :             // Skip if destination is same as source table.
     635     1614638 :             if (dest == table)
     636      667222 :                 continue;
     637             : 
     638     1129188 :             const RoutingInstance *dest_rtinstance = dest->routing_instance();
     639     1129188 :             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     1129856 :             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     1129371 :             BgpRoute *replicated_rt = dest->RouteReplicate(
     656             :                 server_, table, rt, path, new_extcomm_ptr);
     657     1129387 :             if (!replicated_rt)
     658      181774 :                 continue;
     659             : 
     660             :             // Add information about the secondary path to the replicated path
     661             :             // list.
     662      947604 :             RtReplicated::SecondaryRouteInfo rtinfo(dest, path->GetPeer(),
     663     1895207 :                 path->GetPathId(), path->GetSource(), replicated_rt);
     664      947589 :             pair<RtReplicated::ReplicatedRtPathList::iterator, bool> result;
     665      947571 :             result = replicated_path_list.insert(rtinfo);
     666             :             // Assert if the insertion to replication path list fails
     667      947603 :             if (!route_unchanged)
     668      947602 :                 assert(result.second);
     669      947603 :             RPR_TRACE_ONLY(Replicate, table->name(), rt->ToString(),
     670             :                            path->ToString(),
     671             :                            BgpPath::PathIdString(path->GetPathId()),
     672             :                            dest->name(), replicated_rt->ToString());
     673     1129394 :         }
     674      546194 :     }
     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     1266600 :     DBStateSync(table, ts, rt, dbstate, &replicated_path_list);
     679     1267036 :     return true;
     680     1984559 : }
     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        5473 : vector<string> RoutePathReplicator::GetReplicatedTableNameList(
     695             :     const BgpTable *table, const BgpRoute *rt, const BgpPath *path) const {
     696        5473 :     const TableState *ts = FindTableState(table);
     697        5465 :     if (!ts)
     698        5163 :         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      517080 : void RoutePathReplicator::DeleteSecondaryPath(BgpTable *table, BgpRoute *rt,
     707             :     const RtReplicated::SecondaryRouteInfo &rtinfo) {
     708      517080 :     BgpRoute *rt_secondary = rtinfo.rt_;
     709      517080 :     BgpTable *secondary_table = rtinfo.table_;
     710      517080 :     const IPeer *peer = rtinfo.peer_;
     711      517080 :     uint32_t path_id = rtinfo.path_id_;
     712      517080 :     BgpPath::PathSource src = rtinfo.src_;
     713             : 
     714             :     DBTablePartBase *partition =
     715      517080 :         secondary_table->GetTablePartition(rt_secondary);
     716      516989 :     BgpPath *secondary_path = rt_secondary->FindSecondaryPath(rt, src,
     717             :                                                               peer, path_id);
     718      517115 :     if (secondary_path && secondary_path->NeedsResolution()) {
     719           0 :        secondary_table->path_resolver()->StopPathResolution(partition->index(),
     720             :                                                        secondary_path);
     721             :     }
     722      517094 :     assert(rt_secondary->RemoveSecondaryPath(rt, src, peer, path_id));
     723      517409 :     if (rt_secondary->count() == 0) {
     724      493495 :         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      493597 :         partition->Delete(rt_secondary);
     729             :     } else {
     730       23822 :         partition->Notify(rt_secondary);
     731       23822 :         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      517430 : }
     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