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: 139 408 34.1 %
Date: 2026-09-28 02:13:17 Functions: 22 43 51.2 %
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        1890 :     explicit DeleteActor(TableState *ts)
      53        1890 :         : LifetimeActor(ts->replicator()->server()->lifetime_manager()),
      54        1890 :           ts_(ts) {
      55        1890 :     }
      56             : 
      57        1890 :     virtual bool MayDelete() const {
      58        1890 :         return ts_->MayDelete();
      59             :     }
      60             : 
      61        1890 :     virtual void Shutdown() {
      62        1890 :     }
      63             : 
      64        1890 :     virtual void Destroy() {
      65        1890 :         ts_->replicator()->DeleteTableState(ts_->table());
      66        1890 :     }
      67             : 
      68             : private:
      69             :     TableState *ts_;
      70             : };
      71             : 
      72        1890 : TableState::TableState(RoutePathReplicator *replicator, BgpTable *table)
      73        1890 :     : replicator_(replicator),
      74        1890 :       table_(table),
      75        1890 :       listener_id_(DBTableBase::kInvalidId),
      76        1890 :       deleter_(new DeleteActor(this)),
      77        1890 :       table_delete_ref_(this, table->deleter()) {
      78        1890 :     assert(table->deleter() != NULL);
      79        1890 : }
      80             : 
      81        1890 : TableState::~TableState() {
      82        1890 :     if (walk_ref() != NULL) {
      83           0 :         table()->ReleaseWalker(walk_ref());
      84             :     }
      85        1890 : }
      86             : 
      87        1890 : void TableState::ManagedDelete() {
      88        1890 :     deleter()->Delete();
      89        1890 : }
      90             : 
      91           0 : bool TableState::deleted() const {
      92           0 :     return deleter()->IsDeleted();
      93             : }
      94             : 
      95        1906 : LifetimeActor *TableState::deleter() {
      96        1906 :     return deleter_.get();
      97             : }
      98             : 
      99           0 : const LifetimeActor *TableState::deleter() const {
     100           0 :     return deleter_.get();
     101             : }
     102             : 
     103        1890 : bool TableState::MayDelete() const {
     104        3780 :     if (list_.empty() && !route_count() &&
     105        1890 :         ((walk_ref() == NULL) || !walk_ref()->walk_is_active()))
     106        1890 :         return true;
     107           0 :     return false;
     108             : }
     109             : 
     110          16 : void TableState::RetryDelete() {
     111          16 :     if (!deleter()->IsDeleted())
     112          16 :         return;
     113           0 :     deleter()->RetryDelete();
     114             : }
     115             : 
     116           0 : void TableState::AddGroup(RtGroup *group) {
     117           0 :     list_.insert(group);
     118           0 : }
     119             : 
     120           0 : void TableState::RemoveGroup(RtGroup *group) {
     121           0 :     list_.erase(group);
     122           0 : }
     123             : 
     124           0 : const RtGroup *TableState::FindGroup(RtGroup *group) const {
     125           0 :     GroupList::const_iterator it = list_.find(group);
     126           0 :     return (it != list_.end() ? *it : NULL);
     127             : }
     128             : 
     129        1890 : uint32_t TableState::route_count() const {
     130        1890 :     return table_->GetDBStateCount(listener_id());
     131             : }
     132             : 
     133          16 : RtReplicated::RtReplicated(RoutePathReplicator *replicator)
     134          16 :     : replicator_(replicator) {
     135          16 : }
     136             : 
     137           0 : void RtReplicated::AddRouteInfo(BgpTable *table, BgpRoute *rt,
     138             :     ReplicatedRtPathList::const_iterator it) {
     139           0 :     pair<ReplicatedRtPathList::iterator, bool> result;
     140           0 :     result = replicate_list_.insert(*it);
     141           0 :     assert(result.second);
     142           0 : }
     143             : 
     144           0 : void RtReplicated::DeleteRouteInfo(BgpTable *table, BgpRoute *rt,
     145             :     ReplicatedRtPathList::const_iterator it) {
     146           0 :     replicator_->DeleteSecondaryPath(table, rt, *it);
     147           0 :     replicate_list_.erase(it);
     148           0 : }
     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           0 : vector<string> RtReplicated::GetTableNameList(const BgpPath *path) const {
     156           0 :     vector<string> table_list;
     157           0 :     BOOST_FOREACH(const SecondaryRouteInfo &rinfo, replicate_list_) {
     158           0 :         if (rinfo.peer_ != path->GetPeer())
     159           0 :             continue;
     160           0 :         if (rinfo.path_id_ != path->GetPathId())
     161           0 :             continue;
     162           0 :         if (rinfo.src_ != path->GetSource())
     163           0 :             continue;
     164           0 :         table_list.push_back(rinfo.table_->name());
     165             :     }
     166           0 :     return table_list;
     167           0 : }
     168             : 
     169        1890 : RoutePathReplicator::RoutePathReplicator(BgpServer *server,
     170        1890 :     Address::Family family)
     171        1890 :     : server_(server),
     172        1890 :       family_(family),
     173        1890 :       vpn_table_(NULL),
     174        1890 :       trace_buf_(SandeshTraceBufferCreate("RoutePathReplicator", 500)) {
     175        1890 : }
     176             : 
     177        3780 : RoutePathReplicator::~RoutePathReplicator() {
     178        1890 :     assert(table_state_list_.empty());
     179        3780 : }
     180             : 
     181        1890 : void RoutePathReplicator::Initialize() {
     182        1890 :     assert(!vpn_table_);
     183        1890 :     RoutingInstanceMgr *mgr = server_->routing_instance_mgr();
     184        1890 :     assert(mgr);
     185        1890 :     RoutingInstance *master = mgr->GetDefaultRoutingInstance();
     186        1890 :     assert(master);
     187        1890 :     vpn_table_ = master->GetTable(family_);
     188        1890 :     assert(vpn_table_);
     189        1890 :     assert(AddTableState(vpn_table_));
     190        1890 : }
     191             : 
     192        1890 : TableState *RoutePathReplicator::AddTableState(BgpTable *table,
     193             :     RtGroup *group) {
     194        1890 :     assert(table->IsVpnTable() || group);
     195             : 
     196        1890 :     TableStateList::iterator loc = table_state_list_.find(table);
     197        1890 :     if (loc == table_state_list_.end()) {
     198        1890 :         TableState *ts = new TableState(this, table);
     199        1890 :         DBTableBase::ListenerId id = table->Register(
     200             :             boost::bind(&RoutePathReplicator::RouteListener, this, ts, _1, _2),
     201             :             "RoutePathReplicator");
     202        1890 :         ts->set_listener_id(id);
     203        1890 :         if (group)
     204           0 :             ts->AddGroup(group);
     205        1890 :         table_state_list_.insert(make_pair(table, ts));
     206        1890 :         RPR_TRACE(RegTable, table->name());
     207        1890 :         return ts;
     208             :     } else {
     209           0 :         assert(group);
     210           0 :         TableState *ts = loc->second;
     211           0 :         ts->AddGroup(group);
     212           0 :         return ts;
     213             :     }
     214             : }
     215             : 
     216           0 : void RoutePathReplicator::RemoveTableState(BgpTable *table, RtGroup *group) {
     217           0 :     TableState *ts = FindTableState(table);
     218           0 :     assert(ts);
     219           0 :     ts->RemoveGroup(group);
     220           0 : }
     221             : 
     222        1890 : void RoutePathReplicator::DeleteTableState(BgpTable *table) {
     223        1890 :     TableState *ts = FindTableState(table);
     224        1890 :     assert(ts);
     225        1890 :     RPR_TRACE(UnregTable, table->name());
     226        1890 :     table->Unregister(ts->listener_id());
     227        1890 :     table_state_list_.erase(table);
     228        1890 :     delete ts;
     229        1890 : }
     230             : 
     231        1890 : TableState *RoutePathReplicator::FindTableState(BgpTable *table) {
     232        1890 :     TableStateList::iterator loc = table_state_list_.find(table);
     233        1890 :     return (loc != table_state_list_.end() ? loc->second : NULL);
     234             : }
     235             : 
     236           0 : const TableState *RoutePathReplicator::FindTableState(
     237             :     const BgpTable *table) const {
     238             :     TableStateList::const_iterator loc =
     239           0 :         table_state_list_.find(const_cast<BgpTable *>(table));
     240           0 :     return (loc != table_state_list_.end() ? loc->second : NULL);
     241             : }
     242             : 
     243             : void
     244           0 : RoutePathReplicator::RequestWalk(BgpTable *table) {
     245           0 :     CHECK_CONCURRENCY("bgp::Config", "bgp::ConfigHelper");
     246           0 :     TableState *ts = FindTableState(table);
     247           0 :     assert(ts);
     248           0 :     if (!ts->walk_ref()) {
     249             :         DBTable::DBTableWalkRef walk_ref = table->AllocWalker(
     250             :           boost::bind(&RoutePathReplicator::RouteListener, this, ts, _1, _2),
     251           0 :           boost::bind(&RoutePathReplicator::BulkReplicationDone, this, _2));
     252           0 :         table->WalkTable(walk_ref);
     253           0 :         ts->set_walk_ref(walk_ref);
     254           0 :     } else {
     255           0 :         table->WalkAgain(ts->walk_ref());
     256             :     }
     257           0 : }
     258             : 
     259             : void
     260           0 : RoutePathReplicator::BulkReplicationDone(DBTableBase *dbtable) {
     261           0 :     CHECK_CONCURRENCY("db::Walker");
     262           0 :     BgpTable *table = static_cast<BgpTable *>(dbtable);
     263           0 :     RPR_TRACE(WalkDone, table->name());
     264           0 :     TableState *ts = FindTableState(table);
     265           0 :     ts->RetryDelete();
     266           0 : }
     267             : 
     268           0 : void RoutePathReplicator::JoinVpnTable(RtGroup *group) {
     269           0 :     CHECK_CONCURRENCY("bgp::Config", "bgp::ConfigHelper");
     270           0 :     TableState *vpn_ts = FindTableState(vpn_table_);
     271           0 :     if (!vpn_ts || vpn_ts->FindGroup(group))
     272           0 :         return;
     273           0 :     RPR_TRACE(TableJoin, vpn_table_->name(), group->rt().ToString(), true);
     274           0 :     group->AddImportTable(family(), vpn_table_);
     275           0 :     RPR_TRACE(TableJoin, vpn_table_->name(), group->rt().ToString(), false);
     276           0 :     group->AddExportTable(family(), vpn_table_);
     277           0 :     AddTableState(vpn_table_, group);
     278             : }
     279             : 
     280           0 : void RoutePathReplicator::LeaveVpnTable(RtGroup *group) {
     281           0 :     CHECK_CONCURRENCY("bgp::Config", "bgp::ConfigHelper");
     282           0 :     TableState *vpn_ts = FindTableState(vpn_table_);
     283           0 :     if (!vpn_ts)
     284           0 :         return;
     285           0 :     RPR_TRACE(TableLeave, vpn_table_->name(), group->rt().ToString(), true);
     286           0 :     group->RemoveImportTable(family(), vpn_table_);
     287           0 :     RPR_TRACE(TableLeave, vpn_table_->name(), group->rt().ToString(), false);
     288           0 :     group->RemoveExportTable(family(), vpn_table_);
     289           0 :     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           0 : void RoutePathReplicator::Join(BgpTable *table, const RouteTarget &rt,
     298             :                                bool import) {
     299           0 :     CHECK_CONCURRENCY("bgp::Config", "bgp::ConfigHelper");
     300             : 
     301           0 :     std::scoped_lock lock(mutex_);
     302           0 :     RPR_TRACE(TableJoin, table->name(), rt.ToString(), import);
     303             : 
     304           0 :     bool first = false;
     305           0 :     RtGroup *group = server()->rtarget_group_mgr()->LocateRtGroup(rt);
     306           0 :     if (import) {
     307           0 :         first = group->AddImportTable(family(), table);
     308           0 :         if (group->HasDepRoutes())
     309           0 :             server()->rtarget_group_mgr()->NotifyRtGroup(rt);
     310           0 :         if (family_ == Address::INETVPN)
     311           0 :             server_->NotifyAllStaticRoutes();
     312           0 :         BOOST_FOREACH(BgpTable *sec_table, group->GetExportTables(family())) {
     313           0 :             if (sec_table->IsVpnTable() || sec_table->empty())
     314           0 :                 continue;
     315           0 :             RequestWalk(sec_table);
     316             :         }
     317             :     } else {
     318           0 :         first = group->AddExportTable(family(), table);
     319           0 :         AddTableState(table, group);
     320           0 :         if (!table->empty()) {
     321           0 :             RequestWalk(table);
     322             :         }
     323             :     }
     324             : 
     325             :     // Join the vpn table when group is created.
     326           0 :     if (first)
     327           0 :         JoinVpnTable(group);
     328           0 : }
     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           0 : void RoutePathReplicator::Leave(BgpTable *table, const RouteTarget &rt,
     336             :                                 bool import) {
     337           0 :     CHECK_CONCURRENCY("bgp::Config", "bgp::ConfigHelper");
     338             : 
     339           0 :     std::scoped_lock lock(mutex_);
     340           0 :     RtGroup *group = server()->rtarget_group_mgr()->GetRtGroup(rt);
     341           0 :     assert(group);
     342           0 :     RPR_TRACE(TableLeave, table->name(), rt.ToString(), import);
     343             : 
     344           0 :     if (import) {
     345           0 :         group->RemoveImportTable(family(), table);
     346           0 :         if (group->HasDepRoutes())
     347           0 :             server()->rtarget_group_mgr()->NotifyRtGroup(rt);
     348           0 :         if (family_ == Address::INETVPN)
     349           0 :             server_->NotifyAllStaticRoutes();
     350           0 :         BOOST_FOREACH(BgpTable *sec_table, group->GetExportTables(family())) {
     351           0 :             if (sec_table->IsVpnTable() || sec_table->empty())
     352           0 :                 continue;
     353           0 :             RequestWalk(sec_table);
     354             :         }
     355             :     } else {
     356           0 :         group->RemoveExportTable(family(), table);
     357           0 :         RemoveTableState(table, group);
     358           0 :         if (!table->empty()) {
     359           0 :             RequestWalk(table);
     360             :         }
     361             :     }
     362             : 
     363             :     // Leave the vpn table when the last VRF has left the group.
     364           0 :     if (!group->HasVrfTables(family())) {
     365           0 :         LeaveVpnTable(group);
     366           0 :         server()->rtarget_group_mgr()->RemoveRtGroup(rt);
     367             :     }
     368           0 : }
     369             : 
     370          16 : void RoutePathReplicator::DBStateSync(BgpTable *table, TableState *ts,
     371             :     BgpRoute *rt, RtReplicated *dbstate,
     372             :     const RtReplicated::ReplicatedRtPathList *future) {
     373          16 :     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          16 :     if (dbstate->GetList().empty()) {
     378          16 :         rt->ClearState(table, ts->listener_id());
     379          16 :         delete dbstate;
     380          16 :         if (table->GetDBStateCount(ts->listener_id()) == 0)
     381          16 :             ts->RetryDelete();
     382             :     }
     383          16 : }
     384             : 
     385           0 : static ExtCommunityPtr UpdateOriginVn(BgpServer *server,
     386             :                                       const ExtCommunity *ext_community,
     387             :                                       int vn_index) {
     388           0 :     as_t asn = server->autonomous_system();
     389           0 :     ExtCommunityPtr extcomm_ptr;
     390           0 :     if (vn_index) {
     391           0 :         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           0 :             OriginVn origin_vn(asn, vn_index);
     400           0 :             extcomm_ptr = server->extcomm_db()->ReplaceOriginVnAndLocate(
     401           0 :                 ext_community, origin_vn.GetExtCommunity());
     402           0 :             return extcomm_ptr;
     403             :         }
     404             :     }
     405           0 :     extcomm_ptr = server->extcomm_db()->RemoveOriginVnAndLocate(ext_community);
     406           0 :     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          16 : 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          16 :     ExtCommunityPtr extcomm_ptr;
     419          16 :     if (!rtinstance->IsMasterRoutingInstance()) {
     420             :         extcomm_ptr =
     421           0 :             server->extcomm_db()->AppendAndLocate(ext_community, export_list);
     422           0 :         return extcomm_ptr;
     423             :     }
     424             : 
     425             :     // Bail if we have a vpn route without extended communities.
     426          16 :     if (!ext_community)
     427          16 :         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           0 :     BOOST_FOREACH(const ExtCommunity::ExtCommunityValue &comm,
     432             :                   ext_community->communities()) {
     433           0 :         if (!ExtCommunity::is_origin_vn(comm))
     434           0 :             continue;
     435           0 :         OriginVn origin_vn(comm);
     436           0 :         if (!origin_vn.IsGlobal() &&
     437           0 :             origin_vn.as_number() != server->autonomous_system()) {
     438           0 :             continue;
     439             :         }
     440           0 :         return ExtCommunityPtr(ext_community);
     441             :     }
     442             : 
     443             :     // Add the OriginVn if we have a valid vn index.
     444             :     int vn_index =
     445           0 :         server->routing_instance_mgr()->GetVnIndexByExtCommunity(ext_community);
     446           0 :     return UpdateOriginVn(server, ext_community, vn_index);
     447          16 : }
     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          32 : bool RoutePathReplicator::RouteListener(TableState *ts,
     462             :     DBTablePartBase *root, DBEntryBase *entry) {
     463          32 :     CHECK_CONCURRENCY("db::DBTable");
     464             : 
     465          32 :     BgpTable *table = static_cast<BgpTable *>(root->parent());
     466          32 :     BgpRoute *rt = static_cast<BgpRoute *>(entry);
     467          32 :     const RoutingInstance *rtinstance = table->routing_instance();
     468             : 
     469          32 :     DBTableBase::ListenerId id = ts->listener_id();
     470          32 :     assert(id != DBTableBase::kInvalidId);
     471             : 
     472             :     // Get the DBState.
     473             :     RtReplicated *dbstate =
     474          32 :         static_cast<RtReplicated *>(rt->GetState(table, id));
     475          32 :     RtReplicated::ReplicatedRtPathList replicated_path_list;
     476             : 
     477             :     //Flag to track if any change happenned to route in last 30 minutes
     478          32 :     bool route_unchanged = false;
     479             :     //List of tables that needs replication of route
     480          32 :     RtGroup::RtGroupMemberList addedTables;
     481             :     //List of tables that doesn't need replication of route
     482          32 :     RtGroup::RtGroupMemberList deletedTables;
     483             :     //List of tables having the latest changes in route
     484          32 :     RtGroup::RtGroupMemberList previousTables;
     485             :     //Threshold used for optimised replication
     486          32 :     uint64_t optimizationThresholdTime = 30ULL * 60 * 1000000;
     487          32 :     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          32 :     if ( (start - rt->last_update_at() > optimizationThresholdTime) &&
     492             :           dbstate != NULL)
     493             :     {
     494           0 :         RPR_TRACE(RouteListener, "Route change occurred before threshold \
     495             :         time, optimising replication");
     496           0 :         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          32 :     if (!rt->IsUsable() || (table->IsRouteAggregationSupported() &&
     505           0 :                             !rtinstance->deleted() &&
     506           0 :                             table->IsContributingRoute(rt))) {
     507          16 :         if (!dbstate) {
     508          16 :             return true;
     509             :         }
     510           0 :         DBStateSync(table, ts, rt, dbstate, &replicated_path_list);
     511           0 :         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          16 :     if (dbstate == NULL) {
     518          16 :         dbstate = new RtReplicated(this);
     519          16 :         rt->SetState(table, id, dbstate);
     520             :     }
     521             : 
     522             :     // Get the export route target list from the routing instance.
     523          16 :     ExtCommunity::ExtCommunityList export_list;
     524          16 :     if (!rtinstance->IsMasterRoutingInstance()) {
     525           0 :         BOOST_FOREACH(RouteTarget rtarget, rtinstance->GetExportList()) {
     526           0 :             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          16 :     if (route_unchanged){
     533           0 :         replicated_path_list = dbstate->GetList();
     534           0 :         BOOST_FOREACH (RtReplicated::SecondaryRouteInfo path,
     535             :                        replicated_path_list){
     536           0 :             previousTables.insert(path.table_);
     537             :         }
     538             :     }
     539             : 
     540             :     // Replicate all feasible and non-replicated paths.
     541          16 :     for (Route::PathList::iterator it = rt->GetPathList().begin();
     542          64 :         it != rt->GetPathList().end(); ++it) {
     543          16 :         BgpPath *path = static_cast<BgpPath *>(it.operator->());
     544             : 
     545             :         // Skip if the source peer is down.
     546          24 :         if (!path->IsStale() && !path->IsLlgrStale() && path->GetPeer() &&
     547           8 :             !path->GetPeer()->IsReady())
     548          16 :             continue;
     549             : 
     550             :         // No need to replicate aliased or replicated paths.
     551          16 :         if (path->IsReplicated() || path->IsAliased())
     552           0 :             continue;
     553             : 
     554             :         // Do not replicate non-ecmp paths.
     555          16 :         if (rt->BestPath()->PathCompare(*path, true))
     556           0 :             break;
     557             : 
     558             :         // Do not replicate if nexthop is not hitched by ermvpn tree.
     559          16 :         if (path->CheckErmVpn())
     560           0 :             break;
     561             : 
     562          16 :         const BgpAttr *attr = path->GetAttr();
     563          16 :         const ExtCommunity *ext_community = attr->ext_community();
     564             : 
     565             :         ExtCommunityPtr extcomm_ptr =
     566          16 :           UpdateExtCommunity(server(), rtinstance, ext_community, export_list);
     567          16 :         ext_community = extcomm_ptr.get();
     568          16 :         if (!ext_community)
     569          16 :             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           0 :         int vn_index = 0;
     577           0 :         RtGroup::RtGroupMemberList secondary_tables;
     578           0 :         BOOST_FOREACH(const ExtCommunity::ExtCommunityValue &comm,
     579             :                       ext_community->communities()) {
     580           0 :             if (ExtCommunity::is_origin_vn(comm)) {
     581           0 :                 OriginVn origin_vn(comm);
     582           0 :                 vn_index = origin_vn.vn_index();
     583           0 :             } else if (ExtCommunity::is_route_target(comm)) {
     584             :                 RtGroup *group =
     585           0 :                     server()->rtarget_group_mgr()->GetRtGroup(comm);
     586           0 :                 if (!group)
     587           0 :                     continue;
     588             :                 RtGroup::RtGroupMemberList import_list =
     589           0 :                     group->GetImportTables(family());
     590           0 :                 if (import_list.empty())
     591           0 :                     continue;
     592           0 :                 secondary_tables.insert(import_list.begin(), import_list.end());
     593           0 :             }
     594             :         }
     595             : 
     596             :         // Update with family specific secondary tables.
     597           0 :         table->UpdateSecondaryTablesForReplication(rt, &secondary_tables);
     598             : 
     599             :         // Skip if we don't need to replicate the path to any tables.
     600           0 :         if (secondary_tables.empty())
     601           0 :             continue;
     602             : 
     603             :         // Add OriginVn when replicating self-originated routes from a VRF.
     604           0 :         if (!vn_index && !rtinstance->IsMasterRoutingInstance() &&
     605           0 :             path->IsVrfOriginated() && rtinstance->virtual_network_index()) {
     606           0 :             vn_index = rtinstance->virtual_network_index();
     607           0 :             extcomm_ptr = UpdateOriginVn(server_, extcomm_ptr.get(), vn_index);
     608             :         }
     609             : 
     610           0 :         if (route_unchanged){
     611           0 :             addedTables = RtGroup::RtGroupMemberList();
     612             :             // Finding the difference between sets, secondary_tables and
     613             :             // previousTables
     614           0 :             std::set_difference(secondary_tables.begin(), secondary_tables.end(),
     615             :                                 previousTables.begin(), previousTables.end(),
     616             :                                 std::inserter(addedTables, addedTables.end()));
     617           0 :             std::set_difference(previousTables.begin(), previousTables.end(),
     618             :                                 secondary_tables.begin(), secondary_tables.end(),
     619             :                                 std::inserter(deletedTables, deletedTables.end()));
     620           0 :             BOOST_FOREACH (RtReplicated::SecondaryRouteInfo path,
     621             :                        dbstate->GetList()){
     622           0 :                 if (deletedTables.find(path.table_)!=deletedTables.end()) {
     623           0 :                     replicated_path_list.erase(path);
     624             :                 }
     625             :             }
     626             :             //Updating the secondary tables with the difference.
     627           0 :             secondary_tables = addedTables;
     628             : 
     629             :         }
     630             : 
     631             : 
     632             :         // Replicate path to all destination tables.
     633           0 :         BOOST_FOREACH(BgpTable *dest, secondary_tables) {
     634             :             // Skip if destination is same as source table.
     635           0 :             if (dest == table)
     636           0 :                 continue;
     637             : 
     638           0 :             const RoutingInstance *dest_rtinstance = dest->routing_instance();
     639           0 :             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           0 :             if (!vn_index && dest_rtinstance->virtual_network_index() &&
     646           0 :                 dest_rtinstance->HasExportTarget(ext_community)) {
     647           0 :                 int dest_vn_index = dest_rtinstance->virtual_network_index();
     648           0 :                 new_extcomm_ptr = UpdateOriginVn(server_, extcomm_ptr.get(),
     649           0 :                                                  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           0 :             BgpRoute *replicated_rt = dest->RouteReplicate(
     656             :                 server_, table, rt, path, new_extcomm_ptr);
     657           0 :             if (!replicated_rt)
     658           0 :                 continue;
     659             : 
     660             :             // Add information about the secondary path to the replicated path
     661             :             // list.
     662           0 :             RtReplicated::SecondaryRouteInfo rtinfo(dest, path->GetPeer(),
     663           0 :                 path->GetPathId(), path->GetSource(), replicated_rt);
     664           0 :             pair<RtReplicated::ReplicatedRtPathList::iterator, bool> result;
     665           0 :             result = replicated_path_list.insert(rtinfo);
     666             :             // Assert if the insertion to replication path list fails
     667           0 :             if (!route_unchanged)
     668           0 :                 assert(result.second);
     669           0 :             RPR_TRACE_ONLY(Replicate, table->name(), rt->ToString(),
     670             :                            path->ToString(),
     671             :                            BgpPath::PathIdString(path->GetPathId()),
     672             :                            dest->name(), replicated_rt->ToString());
     673           0 :         }
     674          16 :     }
     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          16 :     DBStateSync(table, ts, rt, dbstate, &replicated_path_list);
     679          16 :     return true;
     680          32 : }
     681           0 : const RtReplicated *RoutePathReplicator::GetReplicationState(
     682             :         BgpTable *table, BgpRoute *rt) const {
     683           0 :     const TableState *ts = FindTableState(table);
     684           0 :     if (!ts)
     685           0 :         return NULL;
     686             :     RtReplicated *dbstate =
     687           0 :         static_cast<RtReplicated *>(rt->GetState(table, ts->listener_id()));
     688           0 :     return dbstate;
     689             : }
     690             : 
     691             : //
     692             : // Return the list of secondary table names for the given primary path.
     693             : //
     694           0 : vector<string> RoutePathReplicator::GetReplicatedTableNameList(
     695             :     const BgpTable *table, const BgpRoute *rt, const BgpPath *path) const {
     696           0 :     const TableState *ts = FindTableState(table);
     697           0 :     if (!ts)
     698           0 :         return vector<string>();
     699             :     const RtReplicated *dbstate = static_cast<const RtReplicated *>(
     700           0 :         rt->GetState(table, ts->listener_id()));
     701           0 :     if (!dbstate)
     702           0 :         return vector<string>();
     703           0 :     return dbstate->GetTableNameList(path);
     704             : }
     705             : 
     706           0 : void RoutePathReplicator::DeleteSecondaryPath(BgpTable *table, BgpRoute *rt,
     707             :     const RtReplicated::SecondaryRouteInfo &rtinfo) {
     708           0 :     BgpRoute *rt_secondary = rtinfo.rt_;
     709           0 :     BgpTable *secondary_table = rtinfo.table_;
     710           0 :     const IPeer *peer = rtinfo.peer_;
     711           0 :     uint32_t path_id = rtinfo.path_id_;
     712           0 :     BgpPath::PathSource src = rtinfo.src_;
     713             : 
     714             :     DBTablePartBase *partition =
     715           0 :         secondary_table->GetTablePartition(rt_secondary);
     716           0 :     BgpPath *secondary_path = rt_secondary->FindSecondaryPath(rt, src,
     717             :                                                               peer, path_id);
     718           0 :     if (secondary_path && secondary_path->NeedsResolution()) {
     719           0 :        secondary_table->path_resolver()->StopPathResolution(partition->index(),
     720             :                                                        secondary_path);
     721             :     }
     722           0 :     assert(rt_secondary->RemoveSecondaryPath(rt, src, peer, path_id));
     723           0 :     if (rt_secondary->count() == 0) {
     724           0 :         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           0 :         partition->Delete(rt_secondary);
     729             :     } else {
     730           0 :         partition->Notify(rt_secondary);
     731           0 :         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           0 : }
     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