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: 617 659 93.6 %
Date: 2026-11-09 02:10:49 Functions: 80 85 94.1 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.14