LCOV - code coverage report
Current view: top level - bgp/routing-instance - path_resolver.cc (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 56 659 8.5 %
Date: 2026-09-21 02:11:39 Functions: 12 85 14.1 %
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/path_resolver.h"
       6             : 
       7             : #include <boost/foreach.hpp>
       8             : 
       9             : #include "base/lifetime.h"
      10             : #include "base/set_util.h"
      11             : #include "base/task.h"
      12             : #include "base/task_annotations.h"
      13             : #include "base/task_trigger.h"
      14             : #include "bgp/bgp_log.h"
      15             : #include "bgp/bgp_peer_types.h"
      16             : #include "bgp/bgp_server.h"
      17             : #include "bgp/bgp_table.h"
      18             : #include "bgp/extended-community/vrf_route_import.h"
      19             : #include "bgp/inet/inet_route.h"
      20             : #include "bgp/inet6/inet6_route.h"
      21             : #include "bgp/evpn/evpn_route.h"
      22             : #include "bgp/routing-instance/routing_instance.h"
      23             : #include "bgp/rtarget/rtarget_address.h"
      24             : 
      25             : using std::make_pair;
      26             : using std::string;
      27             : using std::vector;
      28             : 
      29             : //
      30             : // Return true if the prefix for the BgpRoute is the same as given IpAddress.
      31             : //
      32           0 : static bool RoutePrefixIsAddress(Address::Family family, const BgpRoute *route,
      33             :     const IpAddress &address) {
      34           0 :     if (family == Address::INET) {
      35           0 :         const InetRoute *inet_route = static_cast<const InetRoute *>(route);
      36           0 :         if (inet_route->GetPrefix().addr() == address.to_v4() &&
      37           0 :             inet_route->GetPrefix().prefixlen() == Address::kMaxV4PrefixLen) {
      38           0 :             return true;
      39             :         }
      40           0 :     } else if (family == Address::INET6) {
      41           0 :         const Inet6Route *inet6_route = static_cast<const Inet6Route *>(route);
      42           0 :         if (inet6_route->GetPrefix().addr() == address.to_v6() &&
      43           0 :             inet6_route->GetPrefix().prefixlen() == Address::kMaxV6PrefixLen) {
      44           0 :             return true;
      45             :         }
      46           0 :     } else if (family == Address::EVPN) {
      47           0 :         const EvpnRoute *evpn_route = static_cast<const EvpnRoute *>(route);
      48           0 :         if (evpn_route->GetPrefix().family() == Address::INET && address.is_v4()) {
      49           0 :             if (evpn_route->GetPrefix().addr().to_v4() == address.to_v4() &&
      50           0 :                 evpn_route->GetPrefix().prefixlen() == Address::kMaxV4PrefixLen) {
      51           0 :                 return true;
      52             :             }
      53           0 :         } else if (evpn_route->GetPrefix().family() == Address::INET6 &&
      54           0 :                    address.is_v6()) {
      55           0 :             if (evpn_route->GetPrefix().addr().to_v6() == address.to_v6() &&
      56           0 :                 evpn_route->GetPrefix().prefixlen() == Address::kMaxV6PrefixLen) {
      57           0 :                 return true;
      58             :             }
      59             :         }
      60             :     }
      61           0 :     return false;
      62             : }
      63             : 
      64             : // Return true if prefix matches the address.
      65           0 : bool PathResolver::RoutePrefixMatch(const BgpRoute *route,
      66             :                                     const IpAddress &address) {
      67           0 :     const InetRoute *inet_route = dynamic_cast<const InetRoute *>(route);
      68           0 :     if (inet_route) {
      69           0 :         Ip4Prefix prefix(address.to_v4(), Address::kMaxV4PrefixLen);
      70           0 :         return prefix.IsMoreSpecific(inet_route->GetPrefix());
      71             :     }
      72             : 
      73           0 :     const Inet6Route *inet6_route = dynamic_cast<const Inet6Route *>(route);
      74           0 :     if (inet6_route) {
      75           0 :         Inet6Prefix prefix(address.to_v6(), Address::kMaxV6PrefixLen);
      76           0 :         return prefix.IsMoreSpecific(inet6_route->GetPrefix());
      77             :     }
      78             : 
      79           0 :     const EvpnRoute *evpn_route = static_cast<const EvpnRoute *>(route);
      80           0 :     if (evpn_route == nullptr) {
      81           0 :          return false;
      82             :     }
      83           0 :     if (evpn_route->GetPrefix().family() == Address::INET) {
      84           0 :         Ip4Prefix prefix(address.to_v4(), Address::kMaxV4PrefixLen);
      85           0 :         return prefix.IsMoreSpecific(evpn_route->GetPrefix().inet_prefix());
      86           0 :     } else if (evpn_route->GetPrefix().family() == Address::INET6) {
      87           0 :         Inet6Prefix prefix(address.to_v6(), Address::kMaxV6PrefixLen);
      88           0 :         return prefix.IsMoreSpecific(evpn_route->GetPrefix().inet6_prefix());
      89             :     } else {
      90           0 :         return false;
      91             :     }
      92             : }
      93             : 
      94             : class PathResolver::DeleteActor : public LifetimeActor {
      95             : public:
      96         384 :     explicit DeleteActor(PathResolver *resolver)
      97         384 :         : LifetimeActor(resolver->table()->server()->lifetime_manager()),
      98         384 :           resolver_(resolver) {
      99         384 :     }
     100         768 :     virtual ~DeleteActor() {
     101         768 :     }
     102             : 
     103         384 :     virtual bool MayDelete() const {
     104         384 :         return resolver_->MayDelete();
     105             :     }
     106             : 
     107         384 :     virtual void Destroy() {
     108         384 :         resolver_->table()->DestroyPathResolver();
     109         384 :     }
     110             : 
     111             : private:
     112             :     PathResolver *resolver_;
     113             : };
     114             : 
     115             : //
     116             : // Constructor for PathResolver.
     117             : //
     118             : // A new PathResolver is created from BgpTable::CreatePathResolver for inet
     119             : // and inet6 tables in all non-default RoutingInstances.
     120             : //
     121             : // The listener_id if used to set state on BgpRoutes for BgpPaths that have
     122             : // requested resolution.
     123             : //
     124         384 : PathResolver::PathResolver(BgpTable *table)
     125         384 :     : table_(table),
     126         384 :       listener_id_(table->Register(
     127             :           boost::bind(&PathResolver::RouteListener, this, _1, _2),
     128             :           "PathResolver")),
     129         384 :       nexthop_longest_match_(false),
     130         768 :       nexthop_reg_unreg_trigger_(new TaskTrigger(
     131             :           boost::bind(&PathResolver::ProcessResolverNexthopRegUnregList, this),
     132         767 :           TaskScheduler::GetInstance()->GetTaskId("bgp::Config"),
     133         384 :           0)),
     134         767 :       nexthop_update_trigger_(new TaskTrigger(
     135             :           boost::bind(&PathResolver::ProcessResolverNexthopUpdateList, this),
     136         767 :           TaskScheduler::GetInstance()->GetTaskId("bgp::ResolverNexthop"),
     137         384 :           0)),
     138         384 :       deleter_(new DeleteActor(this)),
     139        1535 :       table_delete_ref_(this, table->deleter()) {
     140        1917 :     for (int part_id = 0; part_id < DB::PartitionCount(); ++part_id) {
     141        1532 :         partitions_.push_back(new PathResolverPartition(part_id, this));
     142             :     }
     143         384 : }
     144             : 
     145             : //
     146             : // Destructor for PathResolver.
     147             : //
     148             : // A PathResolver is deleted via LifetimeManager deletion.
     149             : // Actual destruction of the object happens via BgpTable::DestroyPathResolver.
     150             : //
     151             : // Need to do a deep delete of the partitions vector to ensure deletion of all
     152             : // PathResolverPartitions.
     153             : //
     154         384 : PathResolver::~PathResolver() {
     155         384 :     assert(listener_id_ != DBTableBase::kInvalidId);
     156         384 :     table_->Unregister(listener_id_);
     157         384 :     STLDeleteValues(&partitions_);
     158         384 :     nexthop_reg_unreg_trigger_->Reset();
     159         384 :     nexthop_update_trigger_->Reset();
     160         384 : }
     161             : 
     162             : //
     163             : // Get the address family for PathResolver.
     164             : //
     165           0 : Address::Family PathResolver::family() const {
     166           0 :     return table_->family();
     167             : }
     168             : 
     169             : //
     170             : // Request PathResolver to start resolution for the given BgpPath.
     171             : // This API needs to be called explicitly when the BgpPath needs resolution.
     172             : // This is typically when the BgpPath is added, but may also be needed when
     173             : // the BgpPath changes nexthop.
     174             : //
     175           0 : void PathResolver::StartPathResolution(BgpRoute *route, const BgpPath *path,
     176             :         BgpTable *nh_table) {
     177           0 :     CHECK_CONCURRENCY("db::DBTable", "bgp::RouteAggregation",
     178             :         "bgp::Config", "bgp::ConfigHelper");
     179             : 
     180           0 :     if (!nh_table)
     181           0 :         nh_table = table_;
     182           0 :     assert(nh_table->family() == Address::INET ||
     183             :            nh_table->family() == Address::INET6);
     184           0 :     int part_id = route->get_table_partition()->index();
     185           0 :     partitions_[part_id]->StartPathResolution(route, path, nh_table);
     186           0 : }
     187             : 
     188             : //
     189             : // Request PathResolver to stop resolution for the given BgpPath.
     190             : // This API needs to be called explicitly when the BgpPath does not require
     191             : // resolution. This is typically when the BgpPath is deleted, but may also be
     192             : // needed when the BgpPath changes nexthop.
     193             : //
     194           0 : void PathResolver::StopPathResolution(int part_id, const BgpPath *path) {
     195           0 :     CHECK_CONCURRENCY("db::DBTable", "bgp::RouteAggregation",
     196             :         "bgp::Config", "bgp::ConfigHelper");
     197             : 
     198           0 :     partitions_[part_id]->StopPathResolution(path);
     199           0 : }
     200             : 
     201             : //
     202             : // Return the BgpConditionListener for the given family.
     203             : //
     204           0 : BgpConditionListener *PathResolver::get_condition_listener(
     205             :     Address::Family family) {
     206           0 :     return table_->server()->condition_listener(family);
     207             : }
     208             : 
     209             : //
     210             : // Add a ResolverNexthop to the register/unregister list and start the Task
     211             : // to process the list.
     212             : //
     213             : // Note that the operation (register/unregister) is not explicitly part of
     214             : // the list - it's inferred based on the state of the ResolverNexthop when
     215             : // the list is processed.
     216             : //
     217           0 : void PathResolver::RegisterUnregisterResolverNexthop(
     218             :     ResolverNexthop *rnexthop) {
     219           0 :     std::scoped_lock lock(mutex_);
     220           0 :     nexthop_reg_unreg_list_.insert(rnexthop);
     221           0 :     nexthop_reg_unreg_trigger_->Set();
     222           0 : }
     223             : 
     224             : //
     225             : // Add a ResolverNexthop to the update list and start the Task to process the
     226             : // list.
     227             : //
     228           0 : void PathResolver::UpdateResolverNexthop(ResolverNexthop *rnexthop) {
     229           0 :     std::scoped_lock lock(mutex_);
     230           0 :     nexthop_update_list_.insert(rnexthop);
     231           0 :     nexthop_update_trigger_->Set();
     232           0 : }
     233             : 
     234             : //
     235             : // Get the PathResolverPartition for the given part_id.
     236             : //
     237           0 : PathResolverPartition *PathResolver::GetPartition(int part_id) {
     238           0 :     return partitions_[part_id];
     239             : }
     240             : 
     241           0 : PathResolverPartition *PathResolver::GetPartition(int part_id) const {
     242           0 :     return partitions_[part_id];
     243             : }
     244             : 
     245             : //
     246             : // Find ResolverRouteState for the given BgpRoute.
     247             : //
     248           0 : ResolverRouteState *PathResolver::FindResolverRouteState(BgpRoute *route) {
     249             :     ResolverRouteState *state = static_cast<ResolverRouteState *>(
     250           0 :         route->GetState(table_, listener_id_));
     251           0 :     return state;
     252             : }
     253             : 
     254             : //
     255             : // Find or create ResolverRouteState for the given BgpRoute.
     256             : //
     257             : // Note that the refcount for ResolverRouteState gets incremented when the
     258             : // ResolverPath takes an intrusive_ptr to it.
     259             : //
     260           0 : ResolverRouteState *PathResolver::LocateResolverRouteState(BgpRoute *route) {
     261             :     ResolverRouteState *state = static_cast<ResolverRouteState *>(
     262           0 :         route->GetState(table_, listener_id_));
     263           0 :     if (state) {
     264           0 :         return state;
     265             :     } else {
     266           0 :         return (new ResolverRouteState(this, route));
     267             :     }
     268             : }
     269             : 
     270             : //
     271             : // Find or create the ResolverNexthop with the given IpAddress.
     272             : // Called when a new ResolverPath is being created.
     273             : //
     274             : // A newly created ResolverNexthop is added to the map.
     275             : //
     276           0 : ResolverNexthop *PathResolver::LocateResolverNexthop(IpAddress address,
     277             :     BgpTable *table) {
     278           0 :     CHECK_CONCURRENCY("db::DBTable", "bgp::RouteAggregation",
     279             :                       "bgp::Config", "bgp::ConfigHelper");
     280             : 
     281           0 :     std::scoped_lock lock(mutex_);
     282           0 :     ResolverNexthopKey key(address, table);
     283           0 :     ResolverNexthopMap::iterator loc = nexthop_map_.find(key);
     284           0 :     if (loc != nexthop_map_.end()) {
     285           0 :         return loc->second;
     286             :     } else {
     287           0 :         ResolverNexthop *rnexthop = new ResolverNexthop(this, address, table);
     288           0 :         nexthop_map_.insert(make_pair(key, rnexthop));
     289           0 :         return rnexthop;
     290             :     }
     291           0 : }
     292             : 
     293             : //
     294             : // Remove the ResolverNexthop from the map and the update list.
     295             : // Called when ResolverPath is being unregistered from BgpConditionListener
     296             : // as part of register/unregister list processing.
     297             : //
     298             : // If the ResolverNexthop is being unregistered, it's moved to the delete
     299             : // list till the BgpConditionListener invokes the remove complete callback.
     300             : //
     301             : // Note that a ResolverNexthop object cannot be resurrected once it has been
     302             : // removed from the map - it's destined to get destroyed eventually. A new
     303             : // object for the same IpAddress gets created if a new ResolverPath needs to
     304             : // use one.
     305             : //
     306           0 : void PathResolver::RemoveResolverNexthop(ResolverNexthop *rnexthop) {
     307           0 :     CHECK_CONCURRENCY("bgp::Config");
     308             : 
     309           0 :     ResolverNexthopKey key(rnexthop->address(), rnexthop->table());
     310           0 :     ResolverNexthopMap::iterator loc = nexthop_map_.find(key);
     311           0 :     assert(loc != nexthop_map_.end());
     312           0 :     nexthop_map_.erase(loc);
     313           0 :     nexthop_update_list_.erase(rnexthop);
     314           0 : }
     315             : 
     316             : //
     317             : // Callback for BgpConditionListener::RemoveMatchCondition operation for
     318             : // a ResolverNexthop.
     319             : //
     320             : // It's safe to unregister the ResolverNexthop at this point. However the
     321             : // operation cannot be done in the context of db::Walker Task. Enqueue the
     322             : // ResolverNexthop to the register/unregister list.
     323             : //
     324           0 : void PathResolver::UnregisterResolverNexthopDone(BgpTable *table,
     325             :     ConditionMatch *match) {
     326           0 :     CHECK_CONCURRENCY("db::Walker");
     327             : 
     328           0 :     ResolverNexthop *rnexthop = dynamic_cast<ResolverNexthop *>(match);
     329           0 :     assert(rnexthop);
     330           0 :     assert(rnexthop->registered());
     331           0 :     assert(rnexthop->deleted());
     332           0 :     assert(nexthop_delete_list_.find(rnexthop) != nexthop_delete_list_.end());
     333           0 :     RegisterUnregisterResolverNexthop(rnexthop);
     334           0 : }
     335             : 
     336             : //
     337             : // Handle processing of a ResolverNexthop on the register/unregister list.
     338             : //
     339             : // Return true if the ResolverNexthop can be deleted immediately.
     340             : //
     341           0 : bool PathResolver::ProcessResolverNexthopRegUnreg(ResolverNexthop *rnexthop) {
     342           0 :     CHECK_CONCURRENCY("bgp::Config");
     343             : 
     344           0 :     BgpTable *table = rnexthop->table();
     345           0 :     Address::Family family = table->family();
     346           0 :     BgpConditionListener *condition_listener = get_condition_listener(family);
     347             : 
     348           0 :     if (rnexthop->registered()) {
     349           0 :         if (rnexthop->deleted()) {
     350             :             // Unregister the ResolverNexthop from BgpConditionListener since
     351             :             // remove operation has been completed. This is the final step in
     352             :             // the lifetime of ResolverNexthop - the ResolverNexthop will get
     353             :             // deleted when unregister is called.
     354           0 :             nexthop_delete_list_.erase(rnexthop);
     355           0 :             condition_listener->UnregisterMatchCondition(table, rnexthop);
     356           0 :         } else if (rnexthop->empty()) {
     357             :             // Remove the ResolverNexthop from BgpConditionListener as there
     358             :             // are no more ResolverPaths using it. Insert it into the delete
     359             :             // list while remove and unregister operations are still pending.
     360             :             // This prevents premature deletion of the PathResolver itself.
     361             :             // Note that BgpConditionListener marks the ResolverNexthop as
     362             :             // deleted as part of the remove operation.
     363           0 :             RemoveResolverNexthop(rnexthop);
     364           0 :             nexthop_delete_list_.insert(rnexthop);
     365             :             BgpConditionListener::RequestDoneCb cb = boost::bind(
     366           0 :                 &PathResolver::UnregisterResolverNexthopDone, this, _1, _2);
     367           0 :             condition_listener->RemoveMatchCondition(table, rnexthop, cb);
     368           0 :         }
     369             :     } else {
     370           0 :         if (!rnexthop->empty()) {
     371             :             // Register ResolverNexthop to BgpConditionListener since there's
     372             :             // one or more ResolverPaths using it. Skip if the BgpTable is in
     373             :             // the process of being deleted - the BgpConditionListener does
     374             :             // not, and should not need to, handle this scenario.
     375           0 :             if (!table->IsDeleted()) {
     376           0 :                 condition_listener->AddMatchCondition(
     377           0 :                     table, rnexthop, BgpConditionListener::RequestDoneCb());
     378           0 :                 rnexthop->set_registered();
     379             :             }
     380             :         } else {
     381             :             // The ResolverNexthop can be deleted right away since there are
     382             :             // no ResolverPaths using it. This can happen in couple of corner
     383             :             // cases:
     384             :             // 1. ResolverPaths are added and deleted rapidly i.e. before the
     385             :             // ResolverNexthop has been registered with BgpConditionListener.
     386             :             // 2. The ResolverNexthop's BgpTable was in the process of being
     387             :             // deleted when we attempted to register the ResolverNexthop. In
     388             :             // that case, we come here after the last ResolverPath using the
     389             :             // ResolverNexthop has been deleted.
     390           0 :             RemoveResolverNexthop(rnexthop);
     391           0 :             return true;
     392             :         }
     393             :     }
     394             : 
     395           0 :     return false;
     396             : }
     397             : 
     398             : //
     399             : // Handle processing of all ResolverNexthops on the register/unregister list.
     400             : //
     401           0 : bool PathResolver::ProcessResolverNexthopRegUnregList() {
     402           0 :     CHECK_CONCURRENCY("bgp::Config");
     403             : 
     404           0 :     for (ResolverNexthopList::iterator it = nexthop_reg_unreg_list_.begin();
     405           0 :          it != nexthop_reg_unreg_list_.end(); ++it) {
     406           0 :         ResolverNexthop *rnexthop = *it;
     407           0 :         if (ProcessResolverNexthopRegUnreg(rnexthop))
     408           0 :             delete rnexthop;
     409             :     }
     410           0 :     nexthop_reg_unreg_list_.clear();
     411             : 
     412           0 :     RetryDelete();
     413           0 :     return true;
     414             : }
     415             : 
     416             : //
     417             : // Handle processing of all ResolverNexthops on the update list.
     418             : //
     419           0 : bool PathResolver::ProcessResolverNexthopUpdateList() {
     420           0 :     CHECK_CONCURRENCY("bgp::ResolverNexthop");
     421             : 
     422           0 :     for (ResolverNexthopList::iterator it = nexthop_update_list_.begin();
     423           0 :          it != nexthop_update_list_.end(); ++it) {
     424           0 :         ResolverNexthop *rnexthop = *it;
     425           0 :         assert(!rnexthop->deleted());
     426           0 :         rnexthop->TriggerAllResolverPaths();
     427             :     }
     428           0 :     nexthop_update_list_.clear();
     429           0 :     return true;
     430             : }
     431             : 
     432             : //
     433             : // Return true if the DeleteActor is marked deleted.
     434             : //
     435           0 : bool PathResolver::IsDeleted() const {
     436           0 :     return deleter_->IsDeleted();
     437             : }
     438             : 
     439             : //
     440             : // Cascade delete from BgpTable delete_ref to self.
     441             : //
     442         384 : void PathResolver::ManagedDelete() {
     443         384 :     deleter_->Delete();
     444         384 : }
     445             : 
     446             : //
     447             : // Return true if it's safe to delete the PathResolver.
     448             : //
     449         384 : bool PathResolver::MayDelete() const {
     450         384 :     if (!nexthop_map_.empty())
     451           0 :         return false;
     452         384 :     if (!nexthop_delete_list_.empty())
     453           0 :         return false;
     454         384 :     if (!nexthop_reg_unreg_list_.empty())
     455           0 :         return false;
     456         384 :     assert(nexthop_update_list_.empty());
     457         384 :     return true;
     458             : }
     459             : 
     460             : //
     461             : // Attempt to enqueue a delete for the PathResolver.
     462             : //
     463           0 : void PathResolver::RetryDelete() {
     464           0 :     if (!deleter_->IsDeleted())
     465           0 :         return;
     466           0 :     deleter_->RetryDelete();
     467             : }
     468             : 
     469             : //
     470             : // Dummy callback - required in order to get a listener_id for use with
     471             : // BgpConditionListener.
     472             : //
     473         565 : bool PathResolver::RouteListener(DBTablePartBase *root, DBEntryBase *entry) {
     474         565 :     return true;
     475             : }
     476             : 
     477             : //
     478             : // Get size of the map.
     479             : // For testing only.
     480             : //
     481           0 : size_t PathResolver::GetResolverNexthopMapSize() const {
     482           0 :     std::scoped_lock lock(mutex_);
     483           0 :     return nexthop_map_.size();
     484           0 : }
     485             : 
     486             : //
     487             : // Get size of the delete list.
     488             : // For testing only.
     489             : //
     490           0 : size_t PathResolver::GetResolverNexthopDeleteListSize() const {
     491           0 :     std::scoped_lock lock(mutex_);
     492           0 :     return nexthop_delete_list_.size();
     493           0 : }
     494             : 
     495             : //
     496             : // Disable processing of the register/unregister list.
     497             : // For testing only.
     498             : //
     499           0 : void PathResolver::DisableResolverNexthopRegUnregProcessing() {
     500           0 :     nexthop_reg_unreg_trigger_->set_disable();
     501           0 : }
     502             : 
     503             : //
     504             : // Enable processing of the register/unregister list.
     505             : // For testing only.
     506             : //
     507           0 : void PathResolver::EnableResolverNexthopRegUnregProcessing() {
     508           0 :     nexthop_reg_unreg_trigger_->set_enable();
     509           0 : }
     510             : 
     511             : //
     512             : // Get size of the update list.
     513             : // For testing only.
     514             : //
     515           0 : size_t PathResolver::GetResolverNexthopRegUnregListSize() const {
     516           0 :     std::scoped_lock lock(mutex_);
     517           0 :     return nexthop_reg_unreg_list_.size();
     518           0 : }
     519             : 
     520             : //
     521             : // Disable processing of the update list.
     522             : // For testing only.
     523             : //
     524           0 : void PathResolver::DisableResolverNexthopUpdateProcessing() {
     525           0 :     nexthop_update_trigger_->set_disable();
     526           0 : }
     527             : 
     528             : //
     529             : // Enable processing of the update list.
     530             : // For testing only.
     531             : //
     532           0 : void PathResolver::EnableResolverNexthopUpdateProcessing() {
     533           0 :     nexthop_update_trigger_->set_enable();
     534           0 : }
     535             : 
     536             : //
     537             : // Get size of the update list.
     538             : // For testing only.
     539             : //
     540           0 : size_t PathResolver::GetResolverNexthopUpdateListSize() const {
     541           0 :     std::scoped_lock lock(mutex_);
     542           0 :     return nexthop_update_list_.size();
     543           0 : }
     544             : 
     545             : //
     546             : // Disable processing of the path update list in all partitions.
     547             : // For testing only.
     548             : //
     549           0 : void PathResolver::DisableResolverPathUpdateProcessing() {
     550           0 :     for (int part_id = 0; part_id < DB::PartitionCount(); ++part_id) {
     551           0 :         partitions_[part_id]->DisableResolverPathUpdateProcessing();
     552             :     }
     553           0 : }
     554             : 
     555             : //
     556             : // Enable processing of the path update list in all partitions.
     557             : // For testing only.
     558             : //
     559           0 : void PathResolver::EnableResolverPathUpdateProcessing() {
     560           0 :     for (int part_id = 0; part_id < DB::PartitionCount(); ++part_id) {
     561           0 :         partitions_[part_id]->EnableResolverPathUpdateProcessing();
     562             :     }
     563           0 : }
     564             : 
     565             : //
     566             : // Pause processing of the path update list in all partitions.
     567             : // For testing only.
     568             : //
     569           0 : void PathResolver::PauseResolverPathUpdateProcessing() {
     570           0 :     for (int part_id = 0; part_id < DB::PartitionCount(); ++part_id) {
     571           0 :         partitions_[part_id]->PauseResolverPathUpdateProcessing();
     572             :     }
     573           0 : }
     574             : 
     575             : //
     576             : // Resume processing of the path update list in all partitions.
     577             : // For testing only.
     578             : //
     579           0 : void PathResolver::ResumeResolverPathUpdateProcessing() {
     580           0 :     for (int part_id = 0; part_id < DB::PartitionCount(); ++part_id) {
     581           0 :         partitions_[part_id]->ResumeResolverPathUpdateProcessing();
     582             :     }
     583           0 : }
     584             : 
     585             : //
     586             : // Get size of the update list.
     587             : // For testing only.
     588             : //
     589           0 : size_t PathResolver::GetResolverPathUpdateListSize() const {
     590           0 :     size_t total = 0;
     591           0 :     for (int part_id = 0; part_id < DB::PartitionCount(); ++part_id) {
     592           0 :         total += partitions_[part_id]->GetResolverPathUpdateListSize();
     593             :     }
     594           0 :     return total;
     595             : }
     596             : 
     597             : //
     598             : // Fill introspect information.
     599             : //
     600           0 : void PathResolver::FillShowInfo(ShowPathResolver *spr, bool summary) const {
     601           0 :     spr->set_name(table_->name());
     602             : 
     603           0 :     size_t path_count = 0;
     604           0 :     size_t modified_path_count = 0;
     605           0 :     vector<ShowPathResolverPath> sprp_list;
     606           0 :     for (int part_id = 0; part_id < DB::PartitionCount(); ++part_id) {
     607           0 :         const PathResolverPartition *partition = partitions_[part_id];
     608           0 :         path_count += partition->rpath_map_.size();
     609           0 :         modified_path_count += partition->rpath_update_list_.size();
     610           0 :         if (summary)
     611           0 :             continue;
     612           0 :         for (PathResolverPartition::PathToResolverPathMap::const_iterator it =
     613           0 :              partition->rpath_map_.begin(); it != partition->rpath_map_.end();
     614           0 :              ++it) {
     615           0 :             const ResolverPath *rpath = it->second;
     616           0 :             ShowPathResolverPath sprp;
     617           0 :             sprp.set_prefix(rpath->route()->ToString());
     618           0 :             sprp.set_nexthop(rpath->rnexthop()->address().to_string());
     619           0 :             sprp.set_resolved_path_count(rpath->resolved_path_count());
     620           0 :             sprp_list.push_back(sprp);
     621           0 :         }
     622             :     }
     623           0 :     spr->set_path_count(path_count);
     624           0 :     spr->set_modified_path_count(modified_path_count);
     625           0 :     spr->set_nexthop_count(nexthop_map_.size());
     626           0 :     spr->set_modified_nexthop_count(nexthop_reg_unreg_list_.size() +
     627           0 :         nexthop_delete_list_.size() + nexthop_update_list_.size());
     628             : 
     629           0 :     if (summary)
     630           0 :         return;
     631             : 
     632           0 :     vector<ShowPathResolverNexthop> sprn_list;
     633           0 :     for (ResolverNexthopMap::const_iterator it = nexthop_map_.begin();
     634           0 :          it != nexthop_map_.end(); ++it) {
     635           0 :         const ResolverNexthop *rnexthop = it->second;
     636           0 :         const BgpTable *table = rnexthop->table();
     637           0 :         ShowPathResolverNexthop sprn;
     638           0 :         sprn.set_address(rnexthop->address().to_string());
     639           0 :         sprn.set_table(table->name());
     640           0 :         const BgpRoute *route = rnexthop->GetRoute();
     641           0 :         if (route) {
     642           0 :             ShowRouteBrief show_route;
     643           0 :             route->FillRouteInfo(table, &show_route);
     644           0 :             sprn.set_nexthop_route(show_route);
     645           0 :         }
     646           0 :         sprn_list.push_back(sprn);
     647           0 :     }
     648             : 
     649           0 :     spr->set_paths(sprp_list);
     650           0 :     spr->set_nexthops(sprn_list);
     651           0 : }
     652             : 
     653             : //
     654             : //
     655             : // Constructor for PathResolverPartition.
     656             : // A new PathResolverPartition is created when a PathResolver is created.
     657             : //
     658        1534 : PathResolverPartition::PathResolverPartition(int part_id,
     659        1534 :     PathResolver *resolver)
     660        1534 :     : part_id_(part_id),
     661        1534 :       resolver_(resolver),
     662        3068 :       rpath_update_trigger_(new TaskTrigger(
     663             :           boost::bind(&PathResolverPartition::ProcessResolverPathUpdateList,
     664             :               this),
     665        3064 :           TaskScheduler::GetInstance()->GetTaskId("bgp::ResolverPath"),
     666        3069 :           part_id)) {
     667        1534 : }
     668             : 
     669             : //
     670             : // Destructor for PathResolverPartition.
     671             : // All PathResolverPartitions for a PathResolver are destroyed when the
     672             : // PathResolver is destroyed.
     673             : //
     674        1536 : PathResolverPartition::~PathResolverPartition() {
     675        1536 :     assert(rpath_update_list_.empty());
     676        1536 :     rpath_update_trigger_->Reset();
     677        1536 : }
     678             : 
     679             : //
     680             : // Start resolution for the given BgpPath.
     681             : // Create a ResolverPath object and trigger resolution for it.
     682             : // A ResolverNexthop is also created if required.
     683             : //
     684             : // Note that the ResolverPath gets linked to the ResolverNexthop via the
     685             : // ResolverPath constructor.
     686             : //
     687           0 : void PathResolverPartition::StartPathResolution(BgpRoute *route,
     688             :         const BgpPath *path, BgpTable *nh_table) {
     689           0 :     if (!path->IsResolutionFeasible())
     690           0 :         return;
     691           0 :     if (table()->IsDeleted() || nh_table->IsDeleted())
     692           0 :         return;
     693             : 
     694           0 :     Address::Family family = table()->family();
     695           0 :     IpAddress address = path->GetAttr()->nexthop();
     696           0 :     if (table() == nh_table && RoutePrefixIsAddress(family, route, address))
     697           0 :         return;
     698             : 
     699             :     ResolverNexthop *rnexthop;
     700           0 :     if (family != Address::EVPN) {
     701           0 :         rnexthop = resolver_->LocateResolverNexthop(address, nh_table);
     702             :     }
     703             :     else {
     704           0 :         rnexthop = resolver_->LocateResolverNexthop(address, table());
     705             :     }
     706           0 :     assert(!FindResolverPath(path));
     707           0 :     ResolverPath *rpath = CreateResolverPath(path, route, rnexthop);
     708           0 :     TriggerPathResolution(rpath);
     709             : }
     710             : 
     711             : //
     712             : // Stop resolution for the given BgpPath.
     713             : // The ResolverPath is removed from the map right away, but the deletion of
     714             : // any resolved BgpPaths and the ResolverPath itself happens asynchronously.
     715             : //
     716           0 : void PathResolverPartition::StopPathResolution(const BgpPath *path) {
     717           0 :     ResolverPath *rpath = RemoveResolverPath(path);
     718           0 :     if (!rpath)
     719           0 :         return;
     720           0 :     TriggerPathResolution(rpath);
     721             : }
     722             : 
     723             : //
     724             : // Add a ResolverPath to the update list and start Task to process the list.
     725             : //
     726           0 : void PathResolverPartition::TriggerPathResolution(ResolverPath *rpath) {
     727           0 :     CHECK_CONCURRENCY("db::DBTable", "bgp::ResolverNexthop",
     728             :         "bgp::Config", "bgp::ConfigHelper", "bgp::RouteAggregation");
     729             : 
     730           0 :     rpath_update_list_.insert(rpath);
     731           0 :     rpath_update_trigger_->Set();
     732           0 : }
     733             : 
     734             : //
     735             : // Add a ResolverPath to the update list and start Task to process the list.
     736             : // This is used to defer re-evaluation of the ResolverPath when the update
     737             : // list is being processed.
     738             : //
     739           0 : void PathResolverPartition::DeferPathResolution(ResolverPath *rpath) {
     740           0 :     CHECK_CONCURRENCY("bgp::ResolverPath");
     741             : 
     742           0 :     rpath_update_list_.insert(rpath);
     743           0 :     rpath_update_trigger_->Set();
     744           0 : }
     745             : 
     746             : //
     747             : // Get the BgpTable partition corresponding to this PathResolverPartition.
     748             : //
     749           0 : DBTablePartBase *PathResolverPartition::table_partition() {
     750           0 :     return table()->GetTablePartition(part_id_);
     751             : }
     752             : 
     753             : //
     754             : // Create a new ResolverPath for the BgpPath.
     755             : // The ResolverPath is inserted into the map.
     756             : //
     757           0 : ResolverPath *PathResolverPartition::CreateResolverPath(const BgpPath *path,
     758             :     BgpRoute *route, ResolverNexthop *rnexthop) {
     759           0 :     ResolverPath *rpath = new ResolverPath(this, path, route, rnexthop);
     760           0 :     rpath_map_.insert(make_pair(path, rpath));
     761           0 :     return rpath;
     762             : }
     763             : 
     764             : //
     765             : // Find the ResolverPath for given BgpPath.
     766             : //
     767           0 : ResolverPath *PathResolverPartition::FindResolverPath(const BgpPath *path) {
     768           0 :     PathToResolverPathMap::iterator loc = rpath_map_.find(path);
     769           0 :     return (loc != rpath_map_.end() ? loc->second : NULL);
     770             : }
     771             : 
     772             : //
     773             : // Remove the ResolverPath for given BgpPath.
     774             : // The ResolverPath is removed from the map and it's back pointer to the
     775             : // BgpPath is cleared.
     776             : // Actual deletion of the ResolverPath happens asynchronously.
     777             : //
     778           0 : ResolverPath *PathResolverPartition::RemoveResolverPath(const BgpPath *path) {
     779           0 :     PathToResolverPathMap::iterator loc = rpath_map_.find(path);
     780           0 :     if (loc == rpath_map_.end()) {
     781           0 :         return NULL;
     782             :     } else {
     783           0 :         ResolverPath *rpath = loc->second;
     784           0 :         rpath_map_.erase(loc);
     785           0 :         rpath->clear_path();
     786           0 :         return rpath;
     787             :     }
     788             : }
     789             : 
     790             : //
     791             : // Handle processing of all ResolverPaths on the update list.
     792             : //
     793           0 : bool PathResolverPartition::ProcessResolverPathUpdateList() {
     794           0 :     CHECK_CONCURRENCY("bgp::ResolverPath");
     795             : 
     796           0 :     ResolverPathList update_list;
     797           0 :     rpath_update_list_.swap(update_list);
     798           0 :     for (ResolverPathList::iterator it = update_list.begin();
     799           0 :          it != update_list.end(); ++it) {
     800           0 :         ResolverPath *rpath = *it;
     801           0 :         if (rpath->UpdateResolvedPaths())
     802           0 :             delete rpath;
     803             :     }
     804             : 
     805           0 :     return rpath_update_list_.empty();
     806           0 : }
     807             : 
     808             : //
     809             : // Disable processing of the update list.
     810             : // For testing only.
     811             : //
     812           0 : void PathResolverPartition::DisableResolverPathUpdateProcessing() {
     813           0 :     rpath_update_trigger_->set_disable();
     814           0 : }
     815             : 
     816             : //
     817             : // Enable processing of the update list.
     818             : // For testing only.
     819             : //
     820           0 : void PathResolverPartition::EnableResolverPathUpdateProcessing() {
     821           0 :     rpath_update_trigger_->set_enable();
     822           0 : }
     823             : 
     824             : //
     825             : // Pause processing of the update list.
     826             : // For testing only.
     827             : //
     828           0 : void PathResolverPartition::PauseResolverPathUpdateProcessing() {
     829           0 :     rpath_update_trigger_->set_deferred();
     830           0 : }
     831             : 
     832             : //
     833             : // Resume processing of the update list.
     834             : // For testing only.
     835             : //
     836           0 : void PathResolverPartition::ResumeResolverPathUpdateProcessing() {
     837           0 :     rpath_update_trigger_->clear_deferred();
     838           0 : }
     839             : 
     840             : //
     841             : // Get size of the update list.
     842             : // For testing only.
     843             : //
     844           0 : size_t PathResolverPartition::GetResolverPathUpdateListSize() const {
     845           0 :     return rpath_update_list_.size();
     846             : }
     847             : 
     848             : //
     849             : // Constructor for ResolverRouteState.
     850             : // Gets called when the first ResolverPath for a BgpRoute is created.
     851             : //
     852             : // Set State on the BgpRoute to ensure that it doesn't go away.
     853             : //
     854           0 : ResolverRouteState::ResolverRouteState(PathResolver *resolver,
     855           0 :     BgpRoute *route)
     856           0 :     : resolver_(resolver),
     857           0 :       route_(route),
     858           0 :       refcount_(0) {
     859           0 :     route_->SetState(resolver_->table(), resolver_->listener_id(), this);
     860           0 : }
     861             : 
     862             : //
     863             : // Destructor for ResolverRouteState.
     864             : // Gets called via when the refcount goes to 0. This happens when the last
     865             : // ResolverPath for a BgpRoute is deleted.
     866             : //
     867             : // Remove State on the BgpRoute so that deletion can proceed.
     868             : //
     869           0 : ResolverRouteState::~ResolverRouteState() {
     870           0 :     route_->ClearState(resolver_->table(), resolver_->listener_id());
     871           0 : }
     872             : 
     873             : //
     874             : // Constructor for ResolverPath.
     875             : // Add the ResolverPath as a dependent of the ResolverNexthop.
     876             : //
     877             : // Note that it's the caller's responsibility to add the ResolverPath to the
     878             : // map in the PathResolverPartition.
     879             : //
     880           0 : ResolverPath::ResolverPath(PathResolverPartition *partition,
     881           0 :     const BgpPath *path, BgpRoute *route, ResolverNexthop *rnexthop)
     882           0 :     : partition_(partition),
     883           0 :       path_(path),
     884           0 :       route_(route),
     885           0 :       rnexthop_(rnexthop),
     886           0 :       state_(partition_->resolver()->LocateResolverRouteState(route)) {
     887           0 :     rnexthop->AddResolverPath(partition->part_id(), this);
     888           0 : }
     889             : 
     890             : //
     891             : // Destructor for ResolverPath.
     892             : // Remove the ResolverPath as a dependent of the ResolverNexthop. This may
     893             : // trigger unregistration and eventual deletion of the ResolverNexthop if
     894             : // there are no more ResolverPaths using it.
     895             : //
     896             : // Note that the ResolverPath would have been removed from the map in the
     897             : // PathResolverPartition much earlier i.e. when resolution is stopped.
     898             : //
     899           0 : ResolverPath::~ResolverPath() {
     900           0 :     rnexthop_->RemoveResolverPath(partition_->part_id(), this);
     901           0 : }
     902             : 
     903             : //
     904             : // Add the BgpPath specified by the iterator to the resolved path list.
     905             : // Also inserts the BgpPath to the BgpRoute.
     906             : //
     907           0 : void ResolverPath::AddResolvedPath(ResolvedPathList::const_iterator it) {
     908           0 :     BgpPath *path = *it;
     909           0 :     const IPeer *peer = path->GetPeer();
     910           0 :     resolved_path_list_.insert(path);
     911           0 :     route_->InsertPath(path);
     912           0 :     BGP_LOG_STR(BgpMessage, SandeshLevel::SYS_DEBUG, BGP_LOG_FLAG_TRACE,
     913             :         "Added resolved path " << route_->ToString() <<
     914             :         " peer " << (peer ? peer->ToString() : "None") <<
     915             :         " path_id " << BgpPath::PathIdString(path->GetPathId()) <<
     916             :         " nexthop " << path->GetAttr()->nexthop().to_string() <<
     917             :         " label " << path->GetLabel() <<
     918             :         " in table " << partition_->table()->name());
     919           0 : }
     920             : 
     921             : //
     922             : // Delete the BgpPath specified by the iterator from the resolved path list.
     923             : // Also deletes the BgpPath from the BgpRoute.
     924             : //
     925           0 : void ResolverPath::DeleteResolvedPath(ResolvedPathList::const_iterator it) {
     926           0 :     BgpPath *path = *it;
     927           0 :     const IPeer *peer = path->GetPeer();
     928           0 :     BGP_LOG_STR(BgpMessage, SandeshLevel::SYS_DEBUG, BGP_LOG_FLAG_TRACE,
     929             :         "Deleted resolved path " << route_->ToString() <<
     930             :         " peer " << (peer ? peer->ToString() : "None") <<
     931             :         " path_id " << BgpPath::PathIdString(path->GetPathId()) <<
     932             :         " nexthop " << path->GetAttr()->nexthop().to_string() <<
     933             :         " label " << path->GetLabel() <<
     934             :         " in table " << partition_->table()->name());
     935           0 :     route_->DeletePath(path);
     936           0 :     resolved_path_list_.erase(it);
     937           0 : }
     938             : 
     939             : //
     940             : // Find or create the matching resolved BgpPath.
     941             : //
     942           0 : BgpPath *ResolverPath::LocateResolvedPath(const IPeer *peer, uint32_t path_id,
     943             :     const BgpAttr *attr, uint32_t label, bool is_replicated) {
     944           0 :     for (ResolvedPathList::iterator it = resolved_path_list_.begin();
     945           0 :          it != resolved_path_list_.end(); ++it) {
     946           0 :         BgpPath *path = *it;
     947           0 :         if (path->GetPeer() == peer &&
     948           0 :             path->GetPathId() == path_id &&
     949           0 :             path->GetAttr() == attr &&
     950           0 :             path->GetLabel() == label) {
     951           0 :             return path;
     952             :         }
     953             :     }
     954             : 
     955           0 :     BgpPath::PathSource src = path_->GetSource();
     956             :     uint32_t flags =
     957           0 :         (path_->GetFlags() & ~BgpPath::ResolveNexthop) | BgpPath::ResolvedPath;
     958           0 :     if (is_replicated) {
     959           0 :         return (new BgpSecondaryPath(peer, path_id, src, attr, flags, label));
     960             :     } else {
     961           0 :         return (new BgpPath(peer, path_id, src, attr, flags, label));
     962             :     }
     963             : }
     964             : 
     965             : //
     966             : // Return an extended community that's built by combining the values in the
     967             : // original path's attributes with values from the nexthop path's attributes.
     968             : //
     969             : // Pick up the security groups, tunnel encapsulation load balance, source-as
     970             : // and vrf import target values from the nexthop path's attributes.
     971             : //
     972           0 : static ExtCommunityPtr UpdateExtendedCommunity(ExtCommunityDB *extcomm_db,
     973             :     const BgpAttr *attr, const BgpAttr *nh_attr) {
     974           0 :     ExtCommunityPtr ext_community = attr->ext_community();
     975           0 :     const ExtCommunity *nh_ext_community = nh_attr->ext_community();
     976           0 :     if (!nh_ext_community)
     977           0 :         return ext_community;
     978             : 
     979           0 :     ExtCommunity::ExtCommunityList rtarget;
     980           0 :     ExtCommunity::ExtCommunityList sgid_list;
     981           0 :     ExtCommunity::ExtCommunityList encap_list;
     982           0 :     ExtCommunity::ExtCommunityValue const *source_as = NULL;
     983           0 :     ExtCommunity::ExtCommunityValue const *lb = NULL;
     984           0 :     ExtCommunity::ExtCommunityValue const *rt_mac = nullptr;
     985           0 :     BOOST_FOREACH(const ExtCommunity::ExtCommunityValue &value,
     986             :         nh_ext_community->communities()) {
     987           0 :         if (ExtCommunity::is_security_group(value) ||
     988           0 :                 ExtCommunity::is_security_group4(value)) {
     989           0 :             sgid_list.push_back(value);
     990           0 :         } else if (ExtCommunity::is_tunnel_encap(value)) {
     991           0 :             encap_list.push_back(value);
     992           0 :         } else if (ExtCommunity::is_vrf_route_import(value)) {
     993           0 :             VrfRouteImport vit(value);
     994           0 :             rtarget.push_back(RouteTarget(vit.GetIPv4Address(),
     995           0 :                                           vit.GetNumber()).GetExtCommunity());
     996           0 :         } else if (ExtCommunity::is_source_as(value)) {
     997           0 :             source_as = &value;
     998           0 :         } else if (ExtCommunity::is_load_balance(value) && !lb) {
     999           0 :             lb = &value;
    1000           0 :         } else if (ExtCommunity::is_router_mac(value) && !rt_mac) {
    1001           0 :             rt_mac = &value;
    1002             :         }
    1003             :     }
    1004             : 
    1005             :     // Replace rtarget, sgid list, encap list and load balance.
    1006           0 :     ext_community = extcomm_db->ReplaceRTargetAndLocate(ext_community.get(),
    1007           0 :                                                         rtarget);
    1008           0 :     ext_community = extcomm_db->ReplaceSGIDListAndLocate(
    1009           0 :         ext_community.get(), sgid_list);
    1010           0 :     ext_community = extcomm_db->ReplaceTunnelEncapsulationAndLocate(
    1011           0 :         ext_community.get(), encap_list);
    1012           0 :     if (source_as) {
    1013           0 :         ext_community = extcomm_db->ReplaceSourceASAndLocate(
    1014           0 :                 ext_community.get(), *source_as);
    1015             :     }
    1016           0 :     if (lb) {
    1017           0 :         ext_community = extcomm_db->ReplaceLoadBalanceAndLocate(
    1018           0 :             ext_community.get(), *lb);
    1019             :     }
    1020           0 :     if (rt_mac) {
    1021           0 :         ext_community = extcomm_db->AppendAndLocate(
    1022           0 :             ext_community.get(), *rt_mac);
    1023             :     }
    1024           0 :     return ext_community;
    1025           0 : }
    1026             : 
    1027             : //
    1028             : // Update resolved BgpPaths for the ResolverPath based on the BgpRoute for
    1029             : // the ResolverNexthop.
    1030             : //
    1031             : // Return true if the ResolverPath can be deleted.
    1032             : //
    1033             : // Note that the ResolverPath can only be deleted if resolution for it has
    1034             : // been stopped. It must not be deleted simply because there is no viable
    1035             : // BgpRoute for the ResolverNexthop.
    1036             : //
    1037           0 : bool ResolverPath::UpdateResolvedPaths() {
    1038           0 :     CHECK_CONCURRENCY("bgp::ResolverPath");
    1039             : 
    1040             :     // Defer updates if we can't get a write lock on the ResolverRouteState
    1041             :     // for the BgpRoute we're trying to modify.
    1042           0 :     tbb::spin_rw_mutex::scoped_lock rt_write_lock;
    1043           0 :     if (!rt_write_lock.try_acquire(state_->rw_mutex(), true)) {
    1044           0 :         partition_->DeferPathResolution(this);
    1045           0 :         return false;
    1046             :     }
    1047             : 
    1048             :     // Defer updates if we can't get a read lock on the ResolverRouteState
    1049             :     // for the BgpRoute to the ResolverNexthop. This ResolverRouteState will
    1050             :     // exist only if the BgpRoute in question itself has resolved paths.
    1051           0 :     tbb::spin_rw_mutex::scoped_lock nh_read_lock;
    1052           0 :     ResolverRouteState *nh_state = rnexthop_->GetResolverRouteState();
    1053           0 :     if (state_ != nh_state &&
    1054           0 :         nh_state && !nh_read_lock.try_acquire(nh_state->rw_mutex(), false)) {
    1055           0 :         partition_->DeferPathResolution(this);
    1056           0 :         return false;
    1057             :     }
    1058             : 
    1059           0 :     BgpServer *server = partition_->table()->server();
    1060           0 :     BgpAttrDB *attr_db = server->attr_db();
    1061           0 :     ExtCommunityDB *extcomm_db = server->extcomm_db();
    1062             : 
    1063             :     // Go through paths of the nexthop route and build the list of future
    1064             :     // resolved paths. If the nexthop RI is the master instance, indicating
    1065             :     // that we are checking for presence of nexthop in the underlay table, the
    1066             :     // existing path is added to future resolved path as is but with updated
    1067             :     // path flag indicating that it is resolved.
    1068           0 :     ResolvedPathList future_resolved_path_list;
    1069           0 :     const BgpRoute *nh_route = rnexthop_->GetRoute();
    1070           0 :     const IPeer *peer = path_ ? path_->GetPeer() : NULL;
    1071             :     // Process paths of nexthop route if nexthop RI is not the master RI.
    1072           0 :     const RoutingInstance *nh_ri = rnexthop_->table()->routing_instance();
    1073           0 :     bool nh_ri_def = false;
    1074           0 :     if (nh_ri->IsMasterRoutingInstance()) {
    1075           0 :         nh_ri_def = true;
    1076             :     }
    1077           0 :     bool process_paths = false;
    1078           0 :     if (path_ && nh_route && !nh_ri_def) {
    1079           0 :         process_paths = true;
    1080             :     }
    1081             :     Route::PathList::const_iterator it;
    1082           0 :     if (process_paths)
    1083           0 :         it = nh_route->GetPathList().begin();
    1084           0 :     for (; process_paths && it != nh_route->GetPathList().end(); ++it) {
    1085           0 :         const BgpPath *nh_path = static_cast<const BgpPath *>(it.operator->());
    1086             : 
    1087             :         // Start with attributes of the original path.
    1088           0 :         BgpAttrPtr attr(path_->GetAttr());
    1089             : 
    1090             :         // Infeasible nexthop paths are not considered.
    1091           0 :         if (!nh_path->IsFeasible())
    1092           0 :             break;
    1093             : 
    1094             :         // Take snapshot of all ECMP nexthop paths.
    1095           0 :         if (nh_route->BestPath()->PathCompare(*nh_path, true))
    1096           0 :             break;
    1097             : 
    1098             :         // Skip paths with duplicate forwarding information.  This ensures
    1099             :         // that we generate only one path with any given next hop when there
    1100             :         // are multiple nexthop paths from the original source received via
    1101             :         // different peers e.g. directly via XMPP and via BGP.
    1102           0 :         if (nh_route->DuplicateForwardingPath(nh_path))
    1103           0 :             continue;
    1104             : 
    1105             :         // Skip if there's no source rd.
    1106           0 :         RouteDistinguisher source_rd = nh_path->GetSourceRouteDistinguisher();
    1107           0 :         if (source_rd.IsZero())
    1108           0 :             continue;
    1109             : 
    1110             :         // Use source rd from the nexthop path.
    1111           0 :         attr = attr_db->ReplaceSourceRdAndLocate(attr.get(), source_rd);
    1112             : 
    1113             :         // Use nexthop address from the nexthop path.
    1114           0 :         attr = attr_db->ReplaceNexthopAndLocate(attr.get(),
    1115           0 :             nh_path->GetAttr()->nexthop());
    1116             : 
    1117             :         // obtain  extcommunities from original attrs and allow
    1118             :         // route target type values.
    1119           0 :         ExtCommunityPtr ext_community = attr->ext_community();
    1120           0 :         ExtCommunity::ExtCommunityList export_list;
    1121           0 :         if (ext_community)
    1122             :         {
    1123           0 :             BOOST_FOREACH(const ExtCommunity::ExtCommunityValue &v,
    1124             :                ext_community->communities()) {
    1125           0 :                if (!ExtCommunity::is_route_target(v))
    1126           0 :                   continue;
    1127           0 :                export_list.push_back(RouteTarget(v).GetExtCommunity());
    1128             :             }
    1129             :         }
    1130             : 
    1131             :         // Update extended community based on the nexthop path and use it.
    1132             :         ext_community =
    1133           0 :             UpdateExtendedCommunity(extcomm_db, attr.get(), nh_path->GetAttr());
    1134           0 :         if (!export_list.empty()) {
    1135           0 :             ext_community = extcomm_db->AppendAndLocate(ext_community.get(), export_list);
    1136             :         }
    1137           0 :         attr = attr_db->ReplaceExtCommunityAndLocate(attr.get(), ext_community);
    1138             : 
    1139             :         // Locate the resolved path.
    1140           0 :         uint32_t path_id = nh_path->GetAttr()->nexthop().to_v4().to_ulong();
    1141             :         BgpPath *resolved_path =
    1142           0 :             LocateResolvedPath(peer, path_id, attr.get(), nh_path->GetLabel());
    1143           0 :         future_resolved_path_list.insert(resolved_path);
    1144           0 :     }
    1145             : 
    1146             :     // If nexthop RI is the default routing-instance, nothing to update except
    1147             :     // changing path_flags. Locate the resolved path.
    1148           0 :     if (path_ && nh_route && nh_ri_def) {
    1149           0 :         BgpPath *updated_path = LocateResolvedPath(peer, path_->GetPathId(),
    1150           0 :             path_->GetAttr(), path_->GetLabel(), path_->IsReplicated());
    1151           0 :         if (path_->IsReplicated()) {
    1152           0 :             const BgpSecondaryPath *sec_path =
    1153             :                 static_cast<const BgpSecondaryPath *> (path_);
    1154             :             BgpSecondaryPath *sec_upd_path =
    1155           0 :                 dynamic_cast<BgpSecondaryPath *> (updated_path);
    1156           0 :             sec_upd_path->SetReplicateInfo(sec_path->src_table(),
    1157             :                                            sec_path->src_rt());
    1158             :         }
    1159           0 :         future_resolved_path_list.insert(updated_path);
    1160             :     }
    1161             : 
    1162             :     // Reconcile the current and future resolved paths and notify/delete the
    1163             :     // route as appropriate.
    1164           0 :     bool modified = set_synchronize(&resolved_path_list_,
    1165             :         &future_resolved_path_list,
    1166             :         boost::bind(&ResolverPath::AddResolvedPath, this, _1),
    1167             :         boost::bind(&ResolverPath::DeleteResolvedPath, this, _1));
    1168           0 :     if (route_->HasPaths()) {
    1169           0 :         if (modified) {
    1170           0 :             partition_->table_partition()->Notify(route_);
    1171             :         }
    1172             :     } else {
    1173           0 :         partition_->table_partition()->Delete(route_);
    1174             :     }
    1175             : 
    1176           0 :     return (!path_);
    1177           0 : }
    1178             : 
    1179             : //
    1180             : // Constructor for ResolverNexthop.
    1181             : // Initialize the vector of paths_lists to the number of DB partitions.
    1182             : //
    1183           0 : ResolverNexthop::ResolverNexthop(PathResolver *resolver, IpAddress address,
    1184           0 :     BgpTable *table)
    1185           0 :     : resolver_(resolver),
    1186           0 :       address_(address),
    1187           0 :       table_(table),
    1188           0 :       registered_(false),
    1189           0 :       rpath_lists_(DB::PartitionCount()),
    1190           0 :       table_delete_ref_(this, table->deleter()) {
    1191           0 : }
    1192             : 
    1193             : //
    1194             : // Destructor for ResolverNexthop.
    1195             : // A deep delete of the path_lists vector is not required.
    1196             : //
    1197           0 : ResolverNexthop::~ResolverNexthop() {
    1198           0 :     assert(routes_.empty());
    1199           0 : }
    1200             : 
    1201             : //
    1202             : // Implement virtual method for ConditionMatch base class.
    1203             : //
    1204           0 : string ResolverNexthop::ToString() const {
    1205           0 :     return (string("ResolverNexthop ") + address_.to_string());
    1206             : }
    1207             : 
    1208             : //
    1209             : // Implement virtual method for ConditionMatch base class.
    1210             : //
    1211           0 : bool ResolverNexthop::Match(BgpServer *server, BgpTable *table,
    1212             :     BgpRoute *route, bool deleted) {
    1213           0 :     CHECK_CONCURRENCY("db::DBTable");
    1214             : 
    1215             :     // Ignore if the route doesn't match the address.
    1216           0 :     Address::Family family = table->family();
    1217           0 :     assert(family == Address::INET || family == Address::INET6 || family == Address::EVPN);
    1218             : 
    1219             :     // If longest match based lookup is not enabled, do an exact match between
    1220             :     // the route and the address.
    1221           0 :     if (!resolver_->nexthop_longest_match()) {
    1222           0 :         if (!RoutePrefixIsAddress(family, route, address_))
    1223           0 :             return false;
    1224             :     } else {
    1225           0 :         if (!resolver_->RoutePrefixMatch(route, address_))
    1226           0 :             return false;
    1227             :     }
    1228             : 
    1229             :     // Do not resolve over self.
    1230           0 :     if (route->table() == table && route->IsUsable() &&
    1231           0 :             route->BestPath()->GetAttr()->nexthop() == address_) {
    1232           0 :         return false;
    1233             :     }
    1234             : 
    1235             :     // Set or remove MatchState as appropriate.
    1236             :     BgpConditionListener *condition_listener =
    1237           0 :         resolver_->get_condition_listener(family);
    1238           0 :     bool state_added = condition_listener->CheckMatchState(table, route, this);
    1239             : 
    1240             :     // In order to also cover the case when route does not change but its path
    1241             :     // attrs, trigger updates by default, unless non longest matching route is
    1242             :     // inserted or removed.
    1243           0 :     bool longest_match_updated = true;
    1244           0 :     if (deleted) {
    1245           0 :         if (state_added) {
    1246           0 :             longest_match_updated = RemoveRoute(route);
    1247           0 :             condition_listener->RemoveMatchState(table, route, this);
    1248             :         } else {
    1249           0 :             return false;
    1250             :         }
    1251             :     } else {
    1252           0 :         if (!state_added) {
    1253           0 :             longest_match_updated = InsertRoute(route);
    1254           0 :             condition_listener->SetMatchState(table, route, this);
    1255             :         }
    1256             :     }
    1257             : 
    1258             :     // Nothing more to do if the ConditionMatch has been removed.
    1259           0 :     if (ConditionMatch::deleted())
    1260           0 :         return false;
    1261             : 
    1262             :     // Trigger re-evaluation of all dependent ResolverPaths if the longest
    1263             :     // matching route was updated.
    1264           0 :     if (longest_match_updated)
    1265           0 :         resolver_->UpdateResolverNexthop(this);
    1266           0 :     return true;
    1267             : }
    1268             : 
    1269             : //
    1270             : // Add the given ResolverPath to the list of dependents in the partition.
    1271             : // Add to register/unregister list when the first dependent ResolverPath for
    1272             : // the partition is added.
    1273             : //
    1274             : // This may cause the ResolverNexthop to get added to register/unregister
    1275             : // list multiple times - once for the first ResolverPath in each partition.
    1276             : // This case is handled by PathResolver::ProcessResolverNexthopRegUnreg.
    1277             : //
    1278             : // Do not attempt to access other partitions due to concurrency issues.
    1279             : //
    1280           0 : void ResolverNexthop::AddResolverPath(int part_id, ResolverPath *rpath) {
    1281           0 :     CHECK_CONCURRENCY("db::DBTable", "bgp::RouteAggregation",
    1282             :         "bgp::Config", "bgp::ConfigHelper");
    1283             : 
    1284           0 :     if (rpath_lists_[part_id].empty())
    1285           0 :         resolver_->RegisterUnregisterResolverNexthop(this);
    1286           0 :     rpath_lists_[part_id].insert(rpath);
    1287           0 : }
    1288             : 
    1289             : //
    1290             : // Remove given ResolverPath from the list of dependents in the partition.
    1291             : // Add to register/unregister list when the last dependent ResolverPath for
    1292             : // the partition is removed.
    1293             : //
    1294             : // This may cause the ResolverNexthop to get added to register/unregister
    1295             : // list multiple times - once for the last ResolverPath in each partition.
    1296             : // This case is handled by PathResolver::ProcessResolverNexthopRegUnreg.
    1297             : //
    1298             : // Do not attempt to access other partitions due to concurrency issues.
    1299             : //
    1300           0 : void ResolverNexthop::RemoveResolverPath(int part_id, ResolverPath *rpath) {
    1301           0 :     CHECK_CONCURRENCY("bgp::ResolverPath");
    1302             : 
    1303           0 :     rpath_lists_[part_id].erase(rpath);
    1304           0 :     if (rpath_lists_[part_id].empty())
    1305           0 :         resolver_->RegisterUnregisterResolverNexthop(this);
    1306           0 : }
    1307             : 
    1308           0 : ResolverRouteState *ResolverNexthop::GetResolverRouteState() {
    1309           0 :     if (!GetRoute())
    1310           0 :         return NULL;
    1311           0 :     PathResolver *nh_resolver = table_->path_resolver();
    1312           0 :     if (!nh_resolver)
    1313           0 :         return NULL;
    1314           0 :     return nh_resolver->FindResolverRouteState(GetRoute());
    1315             : }
    1316             : 
    1317             : //
    1318             : // Trigger update of resolved BgpPaths for all ResolverPaths that depend on
    1319             : // the ResolverNexthop. Actual update of the resolved BgpPaths happens when
    1320             : // the PathResolverPartitions process their update lists.
    1321             : //
    1322           0 : void ResolverNexthop::TriggerAllResolverPaths() const {
    1323           0 :     CHECK_CONCURRENCY("bgp::ResolverNexthop");
    1324             : 
    1325           0 :     for (int part_id = 0; part_id < DB::PartitionCount(); ++part_id) {
    1326           0 :         for (ResolverPathList::iterator it = rpath_lists_[part_id].begin();
    1327           0 :              it != rpath_lists_[part_id].end(); ++it) {
    1328           0 :             ResolverPath *rpath = *it;
    1329           0 :             resolver_->GetPartition(part_id)->TriggerPathResolution(rpath);
    1330             :         }
    1331             :     }
    1332           0 : }
    1333             : 
    1334             : //
    1335             : // Return true if there are no dependent ResolverPaths in all partitions.
    1336             : //
    1337           0 : bool ResolverNexthop::empty() const {
    1338           0 :     CHECK_CONCURRENCY("bgp::Config");
    1339             : 
    1340           0 :     for (int part_id = 0; part_id < DB::PartitionCount(); ++part_id) {
    1341           0 :         if (!rpath_lists_[part_id].empty())
    1342           0 :             return false;
    1343             :     }
    1344           0 :     return true;
    1345             : }
    1346             : 
    1347           0 : bool ResolverNexthop::ResolverRouteCompare::operator()(
    1348             :         const BgpRoute *lhs, const BgpRoute *rhs) const {
    1349           0 :     const InetRoute *lhs4 = dynamic_cast<const InetRoute *>(lhs);
    1350           0 :     const InetRoute *rhs4 = dynamic_cast<const InetRoute *>(rhs);
    1351           0 :     if (lhs4) {
    1352           0 :         return lhs4->GetPrefix().prefixlen() > rhs4->GetPrefix().prefixlen();
    1353             :     }
    1354             : 
    1355           0 :     const Inet6Route *lhs6 = dynamic_cast<const Inet6Route *>(lhs);
    1356           0 :     const Inet6Route *rhs6 = dynamic_cast<const Inet6Route *>(rhs);
    1357           0 :     if (lhs6) {
    1358           0 :         return lhs6->GetPrefix().prefixlen() > rhs6->GetPrefix().prefixlen();
    1359             :     }
    1360             : 
    1361           0 :     const EvpnRoute *lhs_e = dynamic_cast<const EvpnRoute *>(lhs);
    1362           0 :     const EvpnRoute *rhs_e = dynamic_cast<const EvpnRoute *>(rhs);
    1363           0 :     if (lhs_e != nullptr) {
    1364           0 :         return lhs_e->GetPrefix().ip_address_length() >
    1365           0 :             rhs_e->GetPrefix().ip_address_length();
    1366             :     }
    1367             :     else {
    1368           0 :         return false;
    1369             :     }
    1370             : }
    1371             : 
    1372             : // Insert route into the set of routes sorted based on the prefix length in
    1373             : // descending order. Return true if the route inserted is the new longest match.
    1374           0 : bool ResolverNexthop::InsertRoute(BgpRoute *route) {
    1375           0 :     std::scoped_lock lock(routes_mutex_);
    1376           0 :     routes_.insert(route);
    1377           0 :     bool longest_match = (*(routes_.begin()) == route);
    1378           0 :     return longest_match;
    1379           0 : }
    1380             : 
    1381             : // Remove route from the set of routes sorted based on the prefix length in
    1382             : // descending order. Return true if the route removed was the old longest match.
    1383           0 : bool ResolverNexthop::RemoveRoute(BgpRoute *route) {
    1384           0 :     std::scoped_lock lock(routes_mutex_);
    1385           0 :     bool longest_match = (*(routes_.begin()) == route);
    1386           0 :     routes_.erase(route);
    1387           0 :     return longest_match;
    1388           0 : }
    1389             : 
    1390           0 : const BgpRoute *ResolverNexthop::GetRoute() const {
    1391           0 :     std::scoped_lock lock(routes_mutex_);
    1392           0 :     return !routes_.empty() ? *(routes_.begin()) : NULL;
    1393           0 : }
    1394             : 
    1395           0 : BgpRoute *ResolverNexthop::GetRoute() {
    1396           0 :     std::scoped_lock lock(routes_mutex_);
    1397           0 :     return !routes_.empty() ? *(routes_.begin()) : NULL;
    1398           0 : }

Generated by: LCOV version 1.14