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: 391 416 94.0 %
Date: 2026-11-09 02:10:49 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             :  * Copyright Contributors to the OpenSDN project
       4             :  */
       5             : 
       6             : #include "bgp/routing-instance/routepath_replicator.h"
       7             : 
       8             : #include <boost/foreach.hpp>
       9             : 
      10             : #include <utility>
      11             : 
      12             : #include "base/set_util.h"
      13             : #include "base/task_annotations.h"
      14             : #include "base/task_trigger.h"
      15             : #include "bgp/bgp_config.h"
      16             : #include "bgp/bgp_log.h"
      17             : #include "bgp/bgp_route.h"
      18             : #include "bgp/bgp_server.h"
      19             : #include "bgp/origin-vn/origin_vn.h"
      20             : #include "bgp/routing-instance/path_resolver.h"
      21             : #include "bgp/routing-instance/routing_instance.h"
      22             : #include "bgp/routing-instance/rtarget_group_mgr.h"
      23             : #include "bgp/routing-instance/routing_instance_analytics_types.h"
      24             : 
      25             : using std::ostringstream;
      26             : using std::make_pair;
      27             : using std::pair;
      28             : using std::string;
      29             : using std::vector;
      30             : 
      31             : //
      32             : // RoutePathReplication trace macro. Optionally logs the server name as well for
      33             : // easier debugging in multi server unit tests
      34             : //
      35             : #define RPR_TRACE(obj, ...)                                                    \
      36             : do {                                                                           \
      37             :     if (LoggingDisabled()) break;                                              \
      38             :     bgp_log_test::LogServerName(server());                                     \
      39             :     Rpr##obj##Log::Send("RoutingInstance",                                     \
      40             :             SandeshLevel::SYS_DEBUG, __FILE__, __LINE__, __VA_ARGS__);         \
      41             :     Rpr##obj::TraceMsg(trace_buf_, __FILE__, __LINE__, __VA_ARGS__);           \
      42             : } while (false)
      43             : 
      44             : #define RPR_TRACE_ONLY(obj, ...)                                               \
      45             : do {                                                                           \
      46             :     if (LoggingDisabled()) break;                                              \
      47             :     bgp_log_test::LogServerName(server());                                     \
      48             :     Rpr##obj::TraceMsg(trace_buf_, __FILE__, __LINE__, __VA_ARGS__);           \
      49             : } while (false)
      50             : 
      51             : class TableState::DeleteActor : public LifetimeActor {
      52             : public:
      53      254220 :     explicit DeleteActor(TableState *ts)
      54      254220 :         : LifetimeActor(ts->replicator()->server()->lifetime_manager()),
      55      254220 :           ts_(ts) {
      56      254222 :     }
      57             : 
      58      254307 :     virtual bool MayDelete() const {
      59      254307 :         return ts_->MayDelete();
      60             :     }
      61             : 
      62      254225 :     virtual void Shutdown() {
      63      254225 :     }
      64             : 
      65      254225 :     virtual void Destroy() {
      66      254225 :         ts_->replicator()->DeleteTableState(ts_->table());
      67      254225 :     }
      68             : 
      69             : private:
      70             :     TableState *ts_;
      71             : };
      72             : 
      73      254206 : TableState::TableState(RoutePathReplicator *replicator, BgpTable *table)
      74      254206 :     : replicator_(replicator),
      75      254206 :       table_(table),
      76      254206 :       listener_id_(DBTableBase::kInvalidId),
      77      254206 :       deleter_(new DeleteActor(this)),
      78      254220 :       table_delete_ref_(this, table->deleter()),
      79      254217 :       export_target_gen_(0) {
      80      254207 :     assert(table->deleter() != NULL);
      81      254204 : }
      82             : 
      83      254225 : TableState::~TableState() {
      84      254225 :     if (walk_ref() != NULL) {
      85       22603 :         table()->ReleaseWalker(walk_ref());
      86             :     }
      87      254225 : }
      88             : 
      89      254225 : void TableState::ManagedDelete() {
      90      254225 :     deleter()->Delete();
      91      254225 : }
      92             : 
      93           0 : bool TableState::deleted() const {
      94           0 :     return deleter()->IsDeleted();
      95             : }
      96             : 
      97      910312 : LifetimeActor *TableState::deleter() {
      98      910312 :     return deleter_.get();
      99             : }
     100             : 
     101           0 : const LifetimeActor *TableState::deleter() const {
     102           0 :     return deleter_.get();
     103             : }
     104             : 
     105      254307 : bool TableState::MayDelete() const {
     106      531235 :     if (list_.empty() && !route_count() &&
     107      276928 :         ((walk_ref() == NULL) || !walk_ref()->walk_is_active()))
     108      254225 :         return true;
     109          82 :     return false;
     110             : }
     111             : 
     112      637044 : void TableState::RetryDelete() {
     113      637044 :     if (!deleter()->IsDeleted())
     114      617974 :         return;
     115       19051 :     deleter()->RetryDelete();
     116             : }
     117             : 
     118      668221 : void TableState::AddGroup(RtGroup *group) {
     119      668221 :     list_.insert(group);
     120      668401 : }
     121             : 
     122      668440 : void TableState::RemoveGroup(RtGroup *group) {
     123      668440 :     list_.erase(group);
     124      668439 : }
     125             : 
     126      429494 : const RtGroup *TableState::FindGroup(RtGroup *group) const {
     127      429494 :     GroupList::const_iterator it = list_.find(group);
     128      429448 :     return (it != list_.end() ? *it : NULL);
     129             : }
     130             : 
     131      254318 : uint32_t TableState::route_count() const {
     132      254318 :     return table_->GetDBStateCount(listener_id());
     133             : }
     134             : 
     135     1057887 : RtReplicated::RtReplicated(RoutePathReplicator *replicator)
     136     1057879 :     : replicator_(replicator),
     137     1057887 :       export_target_gen_(0) {
     138     1057845 : }
     139             : 
     140      517638 : void RtReplicated::AddRouteInfo(BgpTable *table, BgpRoute *rt,
     141             :     ReplicatedRtPathList::const_iterator it) {
     142      517638 :     pair<ReplicatedRtPathList::iterator, bool> result;
     143      517639 :     result = replicate_list_.insert(*it);
     144      517676 :     assert(result.second);
     145      517676 : }
     146             : 
     147      517114 : void RtReplicated::DeleteRouteInfo(BgpTable *table, BgpRoute *rt,
     148             :     ReplicatedRtPathList::const_iterator it) {
     149      517114 :     replicator_->DeleteSecondaryPath(table, rt, *it);
     150      517546 :     replicate_list_.erase(it);
     151      517558 : }
     152             : 
     153             : //
     154             : // Return the list of secondary table names for the given primary path.
     155             : // We go through all SecondaryRouteInfos and skip the ones that don't
     156             : // match the primary path.
     157             : //
     158         283 : vector<string> RtReplicated::GetTableNameList(const BgpPath *path) const {
     159         283 :     vector<string> table_list;
     160        1373 :     BOOST_FOREACH(const SecondaryRouteInfo &rinfo, replicate_list_) {
     161         545 :         if (rinfo.peer_ != path->GetPeer())
     162           0 :             continue;
     163         545 :         if (rinfo.path_id_ != path->GetPathId())
     164          16 :             continue;
     165         529 :         if (rinfo.src_ != path->GetSource())
     166           0 :             continue;
     167         529 :         table_list.push_back(rinfo.table_->name());
     168             :     }
     169         283 :     return table_list;
     170           0 : }
     171             : 
     172       48715 : RoutePathReplicator::RoutePathReplicator(BgpServer *server,
     173       48715 :     Address::Family family)
     174       48715 :     : server_(server),
     175       48715 :       family_(family),
     176       48715 :       vpn_table_(NULL),
     177       48715 :       trace_buf_(SandeshTraceBufferCreate("RoutePathReplicator", 500)) {
     178       48715 : }
     179             : 
     180       97430 : RoutePathReplicator::~RoutePathReplicator() {
     181       48715 :     assert(table_state_list_.empty());
     182       97430 : }
     183             : 
     184       41140 : void RoutePathReplicator::Initialize() {
     185       41140 :     assert(!vpn_table_);
     186       41140 :     RoutingInstanceMgr *mgr = server_->routing_instance_mgr();
     187       41140 :     assert(mgr);
     188       41140 :     RoutingInstance *master = mgr->GetDefaultRoutingInstance();
     189       41140 :     assert(master);
     190       41140 :     vpn_table_ = master->GetTable(family_);
     191       41140 :     assert(vpn_table_);
     192       41140 :     assert(AddTableState(vpn_table_));
     193       41140 : }
     194             : 
     195      709527 : TableState *RoutePathReplicator::AddTableState(BgpTable *table,
     196             :     RtGroup *group) {
     197      709527 :     assert(table->IsVpnTable() || group);
     198             : 
     199      709508 :     TableStateList::iterator loc = table_state_list_.find(table);
     200      709228 :     if (loc == table_state_list_.end()) {
     201      254213 :         TableState *ts = new TableState(this, table);
     202      254204 :         DBTableBase::ListenerId id = table->Register(
     203             :             boost::bind(&RoutePathReplicator::RouteListener, this, ts, _1, _2),
     204             :             "RoutePathReplicator");
     205      254196 :         ts->set_listener_id(id);
     206      254193 :         if (group)
     207      213053 :             ts->AddGroup(group);
     208      254216 :         table_state_list_.insert(make_pair(table, ts));
     209      254212 :         RPR_TRACE(RegTable, table->name());
     210      254219 :         return ts;
     211             :     } else {
     212      455178 :         assert(group);
     213      455178 :         TableState *ts = loc->second;
     214      455178 :         ts->AddGroup(group);
     215      455328 :         return ts;
     216             :     }
     217             : }
     218             : 
     219      668439 : void RoutePathReplicator::RemoveTableState(BgpTable *table, RtGroup *group) {
     220      668439 :     TableState *ts = FindTableState(table);
     221      668440 :     assert(ts);
     222      668440 :     ts->RemoveGroup(group);
     223      668439 : }
     224             : 
     225      254225 : void RoutePathReplicator::DeleteTableState(BgpTable *table) {
     226      254225 :     TableState *ts = FindTableState(table);
     227      254225 :     assert(ts);
     228      254225 :     RPR_TRACE(UnregTable, table->name());
     229      254225 :     table->Unregister(ts->listener_id());
     230      254225 :     table_state_list_.erase(table);
     231      254225 :     delete ts;
     232      254225 : }
     233             : 
     234     2097128 : TableState *RoutePathReplicator::FindTableState(BgpTable *table) {
     235     2097128 :     TableStateList::iterator loc = table_state_list_.find(table);
     236     2097028 :     return (loc != table_state_list_.end() ? loc->second : NULL);
     237             : }
     238             : 
     239        5651 : const TableState *RoutePathReplicator::FindTableState(
     240             :     const BgpTable *table) const {
     241             :     TableStateList::const_iterator loc =
     242        5651 :         table_state_list_.find(const_cast<BgpTable *>(table));
     243        5642 :     return (loc != table_state_list_.end() ? loc->second : NULL);
     244             : }
     245             : 
     246             : void
     247       51296 : RoutePathReplicator::RequestWalk(BgpTable *table) {
     248       51296 :     CHECK_CONCURRENCY("bgp::Config", "bgp::ConfigHelper");
     249       51296 :     TableState *ts = FindTableState(table);
     250       51296 :     assert(ts);
     251       51296 :     if (!ts->walk_ref()) {
     252             :         DBTable::DBTableWalkRef walk_ref = table->AllocWalker(
     253             :           boost::bind(&RoutePathReplicator::RouteListener, this, ts, _1, _2),
     254       45206 :           boost::bind(&RoutePathReplicator::BulkReplicationDone, this, _2));
     255       22603 :         table->WalkTable(walk_ref);
     256       22603 :         ts->set_walk_ref(walk_ref);
     257       22603 :     } else {
     258       28693 :         table->WalkAgain(ts->walk_ref());
     259             :     }
     260       51296 : }
     261             : 
     262             : void
     263       24558 : RoutePathReplicator::BulkReplicationDone(DBTableBase *dbtable) {
     264       24558 :     CHECK_CONCURRENCY("db::Walker");
     265       24558 :     BgpTable *table = static_cast<BgpTable *>(dbtable);
     266       24558 :     RPR_TRACE(WalkDone, table->name());
     267       24558 :     TableState *ts = FindTableState(table);
     268       24558 :     ts->RetryDelete();
     269       24558 : }
     270             : 
     271      429921 : void RoutePathReplicator::JoinVpnTable(RtGroup *group) {
     272      429921 :     CHECK_CONCURRENCY("bgp::Config", "bgp::ConfigHelper");
     273      429974 :     TableState *vpn_ts = FindTableState(vpn_table_);
     274      429869 :     if (!vpn_ts || vpn_ts->FindGroup(group))
     275         370 :         return;
     276      429429 :     RPR_TRACE(TableJoin, vpn_table_->name(), group->rt().ToString(), true);
     277      429603 :     group->AddImportTable(family(), vpn_table_);
     278      429764 :     RPR_TRACE(TableJoin, vpn_table_->name(), group->rt().ToString(), false);
     279      429750 :     group->AddExportTable(family(), vpn_table_);
     280      429776 :     AddTableState(vpn_table_, group);
     281             : }
     282             : 
     283      429966 : void RoutePathReplicator::LeaveVpnTable(RtGroup *group) {
     284      429966 :     CHECK_CONCURRENCY("bgp::Config", "bgp::ConfigHelper");
     285      429967 :     TableState *vpn_ts = FindTableState(vpn_table_);
     286      429966 :     if (!vpn_ts)
     287         185 :         return;
     288      429781 :     RPR_TRACE(TableLeave, vpn_table_->name(), group->rt().ToString(), true);
     289      429781 :     group->RemoveImportTable(family(), vpn_table_);
     290      429783 :     RPR_TRACE(TableLeave, vpn_table_->name(), group->rt().ToString(), false);
     291      429783 :     group->RemoveExportTable(family(), vpn_table_);
     292      429784 :     RemoveTableState(vpn_table_, group);
     293             : }
     294             : 
     295             : //
     296             : // Add a given BgpTable to RtGroup of given RouteTarget.
     297             : // It will create a new RtGroup if none exists.
     298             : // In case of export RouteTarget, create TableState if it doesn't exist.
     299             : //
     300      928010 : void RoutePathReplicator::Join(BgpTable *table, const RouteTarget &rt,
     301             :                                bool import) {
     302      928010 :     CHECK_CONCURRENCY("bgp::Config", "bgp::ConfigHelper");
     303             : 
     304      927942 :     std::scoped_lock lock(mutex_);
     305      928526 :     RPR_TRACE(TableJoin, table->name(), rt.ToString(), import);
     306             : 
     307      928549 :     bool first = false;
     308      928549 :     RtGroup *group = server()->rtarget_group_mgr()->LocateRtGroup(rt);
     309      928647 :     if (import) {
     310      689992 :         first = group->AddImportTable(family(), table);
     311      689995 :         if (group->HasDepRoutes())
     312         115 :             server()->rtarget_group_mgr()->NotifyRtGroup(rt);
     313      689862 :         if (family_ == Address::INETVPN)
     314      138000 :             server_->NotifyAllStaticRoutes();
     315     1338432 :         BOOST_FOREACH(BgpTable *sec_table, group->GetExportTables(family())) {
     316      324278 :             if (sec_table->IsVpnTable() || sec_table->empty())
     317      323099 :                 continue;
     318        1171 :             RequestWalk(sec_table);
     319             :         }
     320             :     } else {
     321      238655 :         first = group->AddExportTable(family(), table);
     322      238655 :         TableState *ts = AddTableState(table, group);
     323             :         // Export targets changed, so the attributes of the paths replicated
     324             :         // earlier are stale. Bump before the walk, so that RouteListener does
     325             :         // not take the optimized path for them.
     326      238649 :         ts->bump_export_target_gen();
     327      238653 :         if (!table->empty()) {
     328          60 :             RequestWalk(table);
     329             :         }
     330             :     }
     331             : 
     332             :     // Join the vpn table when group is created.
     333      928182 :     if (first)
     334      429920 :         JoinVpnTable(group);
     335      928376 : }
     336             : 
     337             : //
     338             : // Remove a BgpTable from RtGroup of given RouteTarget.
     339             : // If the last group is going away, the RtGroup will be removed
     340             : // In case of export RouteTarget, trigger remove of TableState appropriate.
     341             : //
     342      928657 : void RoutePathReplicator::Leave(BgpTable *table, const RouteTarget &rt,
     343             :                                 bool import) {
     344      928657 :     CHECK_CONCURRENCY("bgp::Config", "bgp::ConfigHelper");
     345             : 
     346      928653 :     std::scoped_lock lock(mutex_);
     347      928660 :     RtGroup *group = server()->rtarget_group_mgr()->GetRtGroup(rt);
     348      928660 :     assert(group);
     349      928660 :     RPR_TRACE(TableLeave, table->name(), rt.ToString(), import);
     350             : 
     351      928660 :     if (import) {
     352      690005 :         group->RemoveImportTable(family(), table);
     353      690000 :         if (group->HasDepRoutes())
     354      132265 :             server()->rtarget_group_mgr()->NotifyRtGroup(rt);
     355      689998 :         if (family_ == Address::INETVPN)
     356      138001 :             server_->NotifyAllStaticRoutes();
     357     2674026 :         BOOST_FOREACH(BgpTable *sec_table, group->GetExportTables(family())) {
     358      992013 :             if (sec_table->IsVpnTable() || sec_table->empty())
     359      965132 :                 continue;
     360       26882 :             RequestWalk(sec_table);
     361             :         }
     362             :     } else {
     363      238655 :         group->RemoveExportTable(family(), table);
     364      238655 :         RemoveTableState(table, group);
     365             :         // The paths replicated earlier still carry the target being removed.
     366      238655 :         FindTableState(table)->bump_export_target_gen();
     367      238655 :         if (!table->empty()) {
     368       23160 :             RequestWalk(table);
     369             :         }
     370             :     }
     371             : 
     372             :     // Leave the vpn table when the last VRF has left the group.
     373      928654 :     if (!group->HasVrfTables(family())) {
     374      429966 :         LeaveVpnTable(group);
     375      429969 :         server()->rtarget_group_mgr()->RemoveRtGroup(rt);
     376             :     }
     377      928653 : }
     378             : 
     379     1447044 : void RoutePathReplicator::DBStateSync(BgpTable *table, TableState *ts,
     380             :     BgpRoute *rt, RtReplicated *dbstate,
     381             :     const RtReplicated::ReplicatedRtPathList *future) {
     382     1447044 :     set_synchronize(dbstate->GetMutableList(), future,
     383             :         boost::bind(&RtReplicated::AddRouteInfo, dbstate, table, rt, _1),
     384             :         boost::bind(&RtReplicated::DeleteRouteInfo, dbstate, table, rt, _1));
     385             : 
     386     1446938 :     if (dbstate->GetList().empty()) {
     387     1058138 :         rt->ClearState(table, ts->listener_id());
     388     1058352 :         delete dbstate;
     389     1058243 :         if (table->GetDBStateCount(ts->listener_id()) == 0)
     390      612505 :             ts->RetryDelete();
     391             :     }
     392     1447206 : }
     393             : 
     394      225654 : static ExtCommunityPtr UpdateOriginVn(BgpServer *server,
     395             :                                       const ExtCommunity *ext_community,
     396             :                                       int vn_index) {
     397      225654 :     as_t asn = server->autonomous_system();
     398      225663 :     ExtCommunityPtr extcomm_ptr;
     399      225663 :     if (vn_index) {
     400       53603 :         if (asn > AS2_MAX && vn_index > 0xffff) {
     401           0 :             OriginVn origin_vn(asn, AS_TRANS);
     402           0 :             extcomm_ptr = server->extcomm_db()->ReplaceOriginVnAndLocate(
     403           0 :                 ext_community, origin_vn.GetExtCommunity());
     404           0 :             OriginVn origin_vn2(AS_TRANS, vn_index);
     405           0 :             extcomm_ptr = server->extcomm_db()->AppendAndLocate(
     406           0 :                 extcomm_ptr.get(), origin_vn2.GetExtCommunity());
     407           0 :         } else {
     408       53603 :             OriginVn origin_vn(asn, vn_index);
     409      160810 :             extcomm_ptr = server->extcomm_db()->ReplaceOriginVnAndLocate(
     410      107208 :                 ext_community, origin_vn.GetExtCommunity());
     411       53606 :             return extcomm_ptr;
     412             :         }
     413             :     }
     414      172060 :     extcomm_ptr = server->extcomm_db()->RemoveOriginVnAndLocate(ext_community);
     415      172128 :     return extcomm_ptr;
     416           0 : }
     417             : 
     418             : //
     419             : // Update the ExtCommunity with the RouteTargets from the export list
     420             : // and the OriginVn. The OriginVn is derived from the RouteTargets in
     421             : // vpn routes.
     422             : //
     423      517876 : static ExtCommunityPtr UpdateExtCommunity(BgpServer *server,
     424             :         const RoutingInstance *rtinstance, const ExtCommunity *ext_community,
     425             :         const ExtCommunity::ExtCommunityList &export_list) {
     426             :     // Add RouteTargets exported by the instance for a non-master instance.
     427      517876 :     ExtCommunityPtr extcomm_ptr;
     428      517876 :     if (!rtinstance->IsMasterRoutingInstance()) {
     429             :         extcomm_ptr =
     430      322201 :             server->extcomm_db()->AppendAndLocate(ext_community, export_list);
     431      322275 :         return extcomm_ptr;
     432             :     }
     433             : 
     434             :     // Bail if we have a vpn route without extended communities.
     435      195679 :     if (!ext_community)
     436        1051 :         return ExtCommunityPtr(NULL);
     437             : 
     438             :     // Nothing to do if we already have the OriginVn community with our AS
     439             :     // or with a vn index from the global range.
     440     3362036 :     BOOST_FOREACH(const ExtCommunity::ExtCommunityValue &comm,
     441             :                   ext_community->communities()) {
     442     1600256 :         if (!ExtCommunity::is_origin_vn(comm))
     443     1583705 :             continue;
     444       18522 :         OriginVn origin_vn(comm);
     445       37060 :         if (!origin_vn.IsGlobal() &&
     446       18530 :             origin_vn.as_number() != server->autonomous_system()) {
     447        1995 :             continue;
     448             :         }
     449       16535 :         return ExtCommunityPtr(ext_community);
     450             :     }
     451             : 
     452             :     // Add the OriginVn if we have a valid vn index.
     453             :     int vn_index =
     454      178128 :         server->routing_instance_mgr()->GetVnIndexByExtCommunity(ext_community);
     455      178267 :     return UpdateOriginVn(server, ext_community, vn_index);
     456      518193 : }
     457             : 
     458             : //
     459             : // Concurrency: Called in the context of the DB partition task.
     460             : //
     461             : // This function handles
     462             : //   1. Table Notification for path replication
     463             : //   2. Table walk for import/export of new targets
     464             : //
     465             : // Replicate a path (clone the BgpPath) to secondary BgpTables based on the
     466             : // export targets of the primary BgpTable.
     467             : // If primary table is a VRF table attach it's export targets to replicated
     468             : // path in the VPN table.
     469             : //
     470     2009042 : bool RoutePathReplicator::RouteListener(TableState *ts,
     471             :     DBTablePartBase *root, DBEntryBase *entry) {
     472     2009042 :     CHECK_CONCURRENCY("db::DBTable");
     473             : 
     474     2008817 :     BgpTable *table = static_cast<BgpTable *>(root->parent());
     475     2008786 :     BgpRoute *rt = static_cast<BgpRoute *>(entry);
     476     2008786 :     const RoutingInstance *rtinstance = table->routing_instance();
     477             : 
     478     2008742 :     DBTableBase::ListenerId id = ts->listener_id();
     479     2008702 :     assert(id != DBTableBase::kInvalidId);
     480             : 
     481             :     // Get the DBState.
     482             :     RtReplicated *dbstate =
     483     2008702 :         static_cast<RtReplicated *>(rt->GetState(table, id));
     484     2010191 :     RtReplicated::ReplicatedRtPathList replicated_path_list;
     485             : 
     486             :     //Flag to track if any change happenned to route in last 30 minutes
     487     2009719 :     bool route_unchanged = false;
     488             :     //List of tables that needs replication of route
     489     2009719 :     RtGroup::RtGroupMemberList addedTables;
     490             :     //List of tables that doesn't need replication of route
     491     2009098 :     RtGroup::RtGroupMemberList deletedTables;
     492             :     //List of tables having the latest changes in route
     493     2008657 :     RtGroup::RtGroupMemberList previousTables;
     494             :     //Threshold used for optimised replication
     495     2008503 :     uint64_t optimizationThresholdTime = 30ULL * 60 * 1000000;
     496     2008503 :     uint64_t start = UTCTimestampUsec();
     497             :     //Read once: a change racing with this walk must not be recorded as
     498             :     //applied. The walk it requests runs after this one and sees the mismatch.
     499     2010084 :     uint64_t export_target_gen = ts->export_target_gen();
     500             : 
     501             :     //Optimize only if last route change occurred 30 mins before and the
     502             :     //export targets of the primary table are unchanged since the route was
     503             :     //last replicated - the optimized path skips every destination table that
     504             :     //is in both the old and the new set, which for a route in a VRF always
     505             :     //includes the VPN table, leaving it with the previous export targets.
     506             :     //We update the route_unchanged flag to true
     507     2010050 :     if ( (start - rt->last_update_at() > optimizationThresholdTime) &&
     508     2009984 :           dbstate != NULL &&
     509          86 :           dbstate->export_target_gen() == export_target_gen)
     510             :     {
     511          84 :         RPR_TRACE(RouteListener, "Route change occurred before threshold \
     512             :         time, optimising replication");
     513          84 :         route_unchanged = true;
     514             :     }
     515             : 
     516             :     //
     517             :     // Cleanup if the route is not usable.
     518             :     // If route aggregation is enabled, contributing route/more specific route
     519             :     // for a aggregate route will NOT be replicated to destination table
     520             :     //
     521     2472844 :     if (!rt->IsUsable() || (table->IsRouteAggregationSupported() &&
     522      463125 :                             !rtinstance->deleted() &&
     523      460041 :                             table->IsContributingRoute(rt))) {
     524      717505 :         if (!dbstate) {
     525      562838 :             return true;
     526             :         }
     527      154667 :         DBStateSync(table, ts, rt, dbstate, &replicated_path_list);
     528      154656 :         return true;
     529             :     }
     530             : 
     531             :     // Create and set new DBState on the route.  This will get cleaned up via
     532             :     // via the call to DBStateSync if we don't need to replicate the route to
     533             :     // any tables.
     534     1291756 :     if (dbstate == NULL) {
     535     1057893 :         dbstate = new RtReplicated(this);
     536     1057830 :         rt->SetState(table, id, dbstate);
     537             :     }
     538             : 
     539             :     // Get the export route target list from the routing instance.
     540     1292086 :     ExtCommunity::ExtCommunityList export_list;
     541     1292062 :     if (!rtinstance->IsMasterRoutingInstance()) {
     542     5802247 :         BOOST_FOREACH(RouteTarget rtarget, rtinstance->GetExportList()) {
     543     2493647 :             export_list.push_back(rtarget.GetExtCommunity());
     544             :         }
     545             :     }
     546             : 
     547             :     // Updating previousTables with the list of tables having the information
     548             :     // about the route.
     549     1291883 :     if (route_unchanged){
     550          84 :         replicated_path_list = dbstate->GetList();
     551         270 :         BOOST_FOREACH (RtReplicated::SecondaryRouteInfo path,
     552             :                        replicated_path_list){
     553          93 :             previousTables.insert(path.table_);
     554             :         }
     555             :     }
     556             : 
     557             :     // Replicate all feasible and non-replicated paths.
     558     1291883 :     for (Route::PathList::iterator it = rt->GetPathList().begin();
     559     6145510 :         it != rt->GetPathList().end(); ++it) {
     560     1786714 :         BgpPath *path = static_cast<BgpPath *>(it.operator->());
     561             : 
     562             :         // Skip if the source peer is down.
     563     2642028 :         if (!path->IsStale() && !path->IsLlgrStale() && path->GetPeer() &&
     564      854958 :             !path->GetPeer()->IsReady())
     565     1294244 :             continue;
     566             : 
     567             :         // No need to replicate aliased or replicated paths.
     568     1669407 :         if (path->IsReplicated() || path->IsAliased())
     569     1145246 :             continue;
     570             : 
     571             :         // Do not replicate non-ecmp paths.
     572      524148 :         if (rt->BestPath()->PathCompare(*path, true))
     573        6178 :             break;
     574             : 
     575             :         // Do not replicate if nexthop is not hitched by ermvpn tree.
     576      517887 :         if (path->CheckErmVpn())
     577           0 :             break;
     578             : 
     579      517884 :         const BgpAttr *attr = path->GetAttr();
     580      517887 :         const ExtCommunity *ext_community = attr->ext_community();
     581             : 
     582             :         ExtCommunityPtr extcomm_ptr =
     583      517879 :           UpdateExtCommunity(server(), rtinstance, ext_community, export_list);
     584      518193 :         ext_community = extcomm_ptr.get();
     585      518192 :         if (!ext_community)
     586        1051 :             continue;
     587             : 
     588             :         // Go through all extended communities.
     589             :         //
     590             :         // Get the vn_index from the OriginVn extended community.
     591             :         // For each RouteTarget extended community, get the list of tables
     592             :         // to which we need to replicate the path.
     593      517141 :         int vn_index = 0;
     594      517141 :         RtGroup::RtGroupMemberList secondary_tables;
     595     5940347 :         BOOST_FOREACH(const ExtCommunity::ExtCommunityValue &comm,
     596             :                       ext_community->communities()) {
     597     2711578 :             if (ExtCommunity::is_origin_vn(comm)) {
     598       79536 :                 OriginVn origin_vn(comm);
     599       79534 :                 vn_index = origin_vn.vn_index();
     600     2631989 :             } else if (ExtCommunity::is_route_target(comm)) {
     601             :                 RtGroup *group =
     602     2173581 :                     server()->rtarget_group_mgr()->GetRtGroup(comm);
     603     2173953 :                 if (!group)
     604      625029 :                     continue;
     605             :                 RtGroup::RtGroupMemberList import_list =
     606     2171971 :                     group->GetImportTables(family());
     607     2171685 :                 if (import_list.empty())
     608      623047 :                     continue;
     609     1548627 :                 secondary_tables.insert(import_list.begin(), import_list.end());
     610     2171462 :             }
     611             :         }
     612             : 
     613             :         // Update with family specific secondary tables.
     614      517091 :         table->UpdateSecondaryTablesForReplication(rt, &secondary_tables);
     615             : 
     616             :         // Skip if we don't need to replicate the path to any tables.
     617      517088 :         if (secondary_tables.empty())
     618       30298 :             continue;
     619             : 
     620             :         // Add OriginVn when replicating self-originated routes from a VRF.
     621      407459 :         if (!vn_index && !rtinstance->IsMasterRoutingInstance() &&
     622      894246 :             path->IsVrfOriginated() && rtinstance->virtual_network_index()) {
     623       47035 :             vn_index = rtinstance->virtual_network_index();
     624       47035 :             extcomm_ptr = UpdateOriginVn(server_, extcomm_ptr.get(), vn_index);
     625             :         }
     626             : 
     627      486786 :         if (route_unchanged){
     628          86 :             addedTables = RtGroup::RtGroupMemberList();
     629             :             // Finding the difference between sets, secondary_tables and
     630             :             // previousTables
     631          86 :             std::set_difference(secondary_tables.begin(), secondary_tables.end(),
     632             :                                 previousTables.begin(), previousTables.end(),
     633             :                                 std::inserter(addedTables, addedTables.end()));
     634          86 :             std::set_difference(previousTables.begin(), previousTables.end(),
     635             :                                 secondary_tables.begin(), secondary_tables.end(),
     636             :                                 std::inserter(deletedTables, deletedTables.end()));
     637         296 :             BOOST_FOREACH (RtReplicated::SecondaryRouteInfo path,
     638             :                        dbstate->GetList()){
     639         105 :                 if (deletedTables.find(path.table_)!=deletedTables.end()) {
     640           1 :                     replicated_path_list.erase(path);
     641             :                 }
     642             :             }
     643             :             //Updating the secondary tables with the difference.
     644          86 :             secondary_tables = addedTables;
     645             : 
     646             :         }
     647             : 
     648             : 
     649             :         // Replicate path to all destination tables.
     650     3736888 :         BOOST_FOREACH(BgpTable *dest, secondary_tables) {
     651             :             // Skip if destination is same as source table.
     652     1624980 :             if (dest == table)
     653      669176 :                 continue;
     654             : 
     655     1138325 :             const RoutingInstance *dest_rtinstance = dest->routing_instance();
     656     1138325 :             ExtCommunityPtr new_extcomm_ptr = extcomm_ptr;
     657             : 
     658             :             // If the origin vn is unresolved, see if route has a RouteTarget
     659             :             // that's in the set of export RouteTargets for the dest instance.
     660             :             // If so, we set the origin vn for the replicated route to be the
     661             :             // vn for the dest instance.
     662     1139061 :             if (!vn_index && dest_rtinstance->virtual_network_index() &&
     663         468 :                 dest_rtinstance->HasExportTarget(ext_community)) {
     664         368 :                 int dest_vn_index = dest_rtinstance->virtual_network_index();
     665         736 :                 new_extcomm_ptr = UpdateOriginVn(server_, extcomm_ptr.get(),
     666         368 :                                                  dest_vn_index);
     667             :             }
     668             : 
     669             :             // Replicate the route to the destination table.  The destination
     670             :             // table may decide to not replicate based on it's own policy e.g.
     671             :             // multicast routes are never leaked across routing-instances.
     672     1138580 :             BgpRoute *replicated_rt = dest->RouteReplicate(
     673             :                 server_, table, rt, path, new_extcomm_ptr);
     674     1138600 :             if (!replicated_rt)
     675      182533 :                 continue;
     676             : 
     677             :             // Add information about the secondary path to the replicated path
     678             :             // list.
     679      956053 :             RtReplicated::SecondaryRouteInfo rtinfo(dest, path->GetPeer(),
     680     1912116 :                 path->GetPathId(), path->GetSource(), replicated_rt);
     681      956043 :             pair<RtReplicated::ReplicatedRtPathList::iterator, bool> result;
     682      956028 :             result = replicated_path_list.insert(rtinfo);
     683             :             // Assert if the insertion to replication path list fails
     684      956034 :             if (!route_unchanged)
     685      956034 :                 assert(result.second);
     686      956034 :             RPR_TRACE_ONLY(Replicate, table->name(), rt->ToString(),
     687             :                            path->ToString(),
     688             :                            BgpPath::PathIdString(path->GetPathId()),
     689             :                            dest->name(), replicated_rt->ToString());
     690     1138599 :         }
     691      548487 :     }
     692             : 
     693             :     // Record what this replication was done with, for the next walk.
     694     1291979 :     dbstate->set_export_target_gen(export_target_gen);
     695             : 
     696             :     // Update the DBState to reflect the new list of secondary paths. The
     697             :     // DBState will get cleared if the list is empty.
     698     1292303 :     DBStateSync(table, ts, rt, dbstate, &replicated_path_list);
     699     1292396 :     return true;
     700     2009890 : }
     701         176 : const RtReplicated *RoutePathReplicator::GetReplicationState(
     702             :         BgpTable *table, BgpRoute *rt) const {
     703         176 :     const TableState *ts = FindTableState(table);
     704         176 :     if (!ts)
     705           0 :         return NULL;
     706             :     RtReplicated *dbstate =
     707         176 :         static_cast<RtReplicated *>(rt->GetState(table, ts->listener_id()));
     708         176 :     return dbstate;
     709             : }
     710             : 
     711             : //
     712             : // Return the list of secondary table names for the given primary path.
     713             : //
     714        5475 : vector<string> RoutePathReplicator::GetReplicatedTableNameList(
     715             :     const BgpTable *table, const BgpRoute *rt, const BgpPath *path) const {
     716        5475 :     const TableState *ts = FindTableState(table);
     717        5465 :     if (!ts)
     718        5161 :         return vector<string>();
     719             :     const RtReplicated *dbstate = static_cast<const RtReplicated *>(
     720         304 :         rt->GetState(table, ts->listener_id()));
     721         304 :     if (!dbstate)
     722          21 :         return vector<string>();
     723         283 :     return dbstate->GetTableNameList(path);
     724             : }
     725             : 
     726      517098 : void RoutePathReplicator::DeleteSecondaryPath(BgpTable *table, BgpRoute *rt,
     727             :     const RtReplicated::SecondaryRouteInfo &rtinfo) {
     728      517098 :     BgpRoute *rt_secondary = rtinfo.rt_;
     729      517098 :     BgpTable *secondary_table = rtinfo.table_;
     730      517098 :     const IPeer *peer = rtinfo.peer_;
     731      517098 :     uint32_t path_id = rtinfo.path_id_;
     732      517098 :     BgpPath::PathSource src = rtinfo.src_;
     733             : 
     734             :     DBTablePartBase *partition =
     735      517098 :         secondary_table->GetTablePartition(rt_secondary);
     736      517032 :     BgpPath *secondary_path = rt_secondary->FindSecondaryPath(rt, src,
     737             :                                                               peer, path_id);
     738      517198 :     if (secondary_path && secondary_path->NeedsResolution()) {
     739           0 :        secondary_table->path_resolver()->StopPathResolution(partition->index(),
     740             :                                                        secondary_path);
     741             :     }
     742      517180 :     assert(rt_secondary->RemoveSecondaryPath(rt, src, peer, path_id));
     743      517512 :     if (rt_secondary->count() == 0) {
     744      493456 :         RPR_TRACE_ONLY(Flush, secondary_table->name(), rt_secondary->ToString(),
     745             :                        peer ? peer->ToString() : "Nil",
     746             :                        BgpPath::PathIdString(path_id), table->name(),
     747             :                        rt->ToString(), "Delete");
     748      493661 :         partition->Delete(rt_secondary);
     749             :     } else {
     750       23888 :         partition->Notify(rt_secondary);
     751       23896 :         RPR_TRACE_ONLY(Flush, secondary_table->name(), rt_secondary->ToString(),
     752             :                        peer ? peer->ToString() : "Nil",
     753             :                        BgpPath::PathIdString(path_id), table->name(),
     754             :                        rt->ToString(), "Path update");
     755             :     }
     756      517562 : }
     757             : 
     758           0 : string RtReplicated::SecondaryRouteInfo::ToString() const {
     759           0 :     ostringstream out;
     760           0 :     out << table_->name() << "(" << table_ << ")" << ":" <<
     761           0 :         peer_->ToString() << "(" << peer_ << ")" << ":" <<
     762           0 :         rt_->ToString() << "(" << rt_ << ")";
     763           0 :     return out.str();
     764           0 : }

Generated by: LCOV version 1.14