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-06-08 02:02:55 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             :  */
       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       52307 : static bool RoutePrefixIsAddress(Address::Family family, const BgpRoute *route,
      33             :     const IpAddress &address) {
      34       52307 :     if (family == Address::INET) {
      35       38186 :         const InetRoute *inet_route = static_cast<const InetRoute *>(route);
      36       42359 :         if (inet_route->GetPrefix().addr() == address.to_v4() &&
      37        4141 :             inet_route->GetPrefix().prefixlen() == Address::kMaxV4PrefixLen) {
      38        4141 :             return true;
      39             :         }
      40       14121 :     } else if (family == Address::INET6) {
      41        1418 :         const Inet6Route *inet6_route = static_cast<const Inet6Route *>(route);
      42        1742 :         if (inet6_route->GetPrefix().addr() == address.to_v6() &&
      43         324 :             inet6_route->GetPrefix().prefixlen() == Address::kMaxV6PrefixLen) {
      44         324 :             return true;
      45             :         }
      46       12703 :     } else if (family == Address::EVPN) {
      47       12703 :         const EvpnRoute *evpn_route = static_cast<const EvpnRoute *>(route);
      48       12703 :         if (evpn_route->GetPrefix().family() == Address::INET && address.is_v4()) {
      49        8736 :             if (evpn_route->GetPrefix().addr().to_v4() == address.to_v4() &&
      50         750 :                 evpn_route->GetPrefix().prefixlen() == Address::kMaxV4PrefixLen) {
      51         750 :                 return true;
      52             :             }
      53        9465 :         } else if (evpn_route->GetPrefix().family() == Address::INET6 &&
      54        4733 :                    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       47143 :     return false;
      62             : }
      63             : 
      64             : // Return true if prefix matches the address.
      65         291 : bool PathResolver::RoutePrefixMatch(const BgpRoute *route,
      66             :                                     const IpAddress &address) {
      67         291 :     const InetRoute *inet_route = dynamic_cast<const InetRoute *>(route);
      68         291 :     if (inet_route) {
      69         237 :         Ip4Prefix prefix(address.to_v4(), Address::kMaxV4PrefixLen);
      70         237 :         return prefix.IsMoreSpecific(inet_route->GetPrefix());
      71             :     }
      72             : 
      73          54 :     const Inet6Route *inet6_route = dynamic_cast<const Inet6Route *>(route);
      74          54 :     if (inet6_route) {
      75          54 :         Inet6Prefix prefix(address.to_v6(), Address::kMaxV6PrefixLen);
      76          54 :         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      171603 :     explicit DeleteActor(PathResolver *resolver)
      97      171603 :         : LifetimeActor(resolver->table()->server()->lifetime_manager()),
      98      171603 :           resolver_(resolver) {
      99      171620 :     }
     100      343248 :     virtual ~DeleteActor() {
     101      343248 :     }
     102             : 
     103      171730 :     virtual bool MayDelete() const {
     104      171730 :         return resolver_->MayDelete();
     105             :     }
     106             : 
     107      171624 :     virtual void Destroy() {
     108      171624 :         resolver_->table()->DestroyPathResolver();
     109      171624 :     }
     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      171614 : PathResolver::PathResolver(BgpTable *table)
     125      171614 :     : table_(table),
     126      171614 :       listener_id_(table->Register(
     127             :           boost::bind(&PathResolver::RouteListener, this, _1, _2),
     128             :           "PathResolver")),
     129      171587 :       nexthop_longest_match_(false),
     130      343199 :       nexthop_reg_unreg_trigger_(new TaskTrigger(
     131             :           boost::bind(&PathResolver::ProcessResolverNexthopRegUnregList, this),
     132      343199 :           TaskScheduler::GetInstance()->GetTaskId("bgp::Config"),
     133      171619 :           0)),
     134      343216 :       nexthop_update_trigger_(new TaskTrigger(
     135             :           boost::bind(&PathResolver::ProcessResolverNexthopUpdateList, this),
     136      343205 :           TaskScheduler::GetInstance()->GetTaskId("bgp::ResolverNexthop"),
     137      171621 :           0)),
     138      171600 :       deleter_(new DeleteActor(this)),
     139      686426 :       table_delete_ref_(this, table->deleter()) {
     140      854984 :     for (int part_id = 0; part_id < DB::PartitionCount(); ++part_id) {
     141      683410 :         partitions_.push_back(new PathResolverPartition(part_id, this));
     142             :     }
     143      171535 : }
     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      171624 : PathResolver::~PathResolver() {
     155      171624 :     assert(listener_id_ != DBTableBase::kInvalidId);
     156      171624 :     table_->Unregister(listener_id_);
     157      171624 :     STLDeleteValues(&partitions_);
     158      171624 :     nexthop_reg_unreg_trigger_->Reset();
     159      171624 :     nexthop_update_trigger_->Reset();
     160      171624 : }
     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        3052 : void PathResolver::StartPathResolution(BgpRoute *route, const BgpPath *path,
     176             :         BgpTable *nh_table) {
     177        3052 :     CHECK_CONCURRENCY("db::DBTable", "bgp::RouteAggregation",
     178             :         "bgp::Config", "bgp::ConfigHelper");
     179             : 
     180        3053 :     if (!nh_table)
     181         166 :         nh_table = table_;
     182        3053 :     assert(nh_table->family() == Address::INET ||
     183             :            nh_table->family() == Address::INET6);
     184        3052 :     int part_id = route->get_table_partition()->index();
     185        3051 :     partitions_[part_id]->StartPathResolution(route, path, nh_table);
     186        3053 : }
     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        3052 : void PathResolver::StopPathResolution(int part_id, const BgpPath *path) {
     195        3052 :     CHECK_CONCURRENCY("db::DBTable", "bgp::RouteAggregation",
     196             :         "bgp::Config", "bgp::ConfigHelper");
     197             : 
     198        3053 :     partitions_[part_id]->StopPathResolution(path);
     199        3053 : }
     200             : 
     201             : //
     202             : // Return the BgpConditionListener for the given family.
     203             : //
     204        9597 : BgpConditionListener *PathResolver::get_condition_listener(
     205             :     Address::Family family) {
     206        9597 :     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        4183 : void PathResolver::RegisterUnregisterResolverNexthop(
     218             :     ResolverNexthop *rnexthop) {
     219        4183 :     std::scoped_lock lock(mutex_);
     220        4183 :     nexthop_reg_unreg_list_.insert(rnexthop);
     221        4183 :     nexthop_reg_unreg_trigger_->Set();
     222        4183 : }
     223             : 
     224             : //
     225             : // Add a ResolverNexthop to the update list and start the Task to process the
     226             : // list.
     227             : //
     228        4997 : void PathResolver::UpdateResolverNexthop(ResolverNexthop *rnexthop) {
     229        4997 :     std::scoped_lock lock(mutex_);
     230        4997 :     nexthop_update_list_.insert(rnexthop);
     231        4997 :     nexthop_update_trigger_->Set();
     232        4997 : }
     233             : 
     234             : //
     235             : // Get the PathResolverPartition for the given part_id.
     236             : //
     237        5865 : PathResolverPartition *PathResolver::GetPartition(int part_id) {
     238        5865 :     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        7953 : ResolverRouteState *PathResolver::FindResolverRouteState(BgpRoute *route) {
     249             :     ResolverRouteState *state = static_cast<ResolverRouteState *>(
     250        7953 :         route->GetState(table_, listener_id_));
     251        7953 :     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        3043 : ResolverRouteState *PathResolver::LocateResolverRouteState(BgpRoute *route) {
     261             :     ResolverRouteState *state = static_cast<ResolverRouteState *>(
     262        3043 :         route->GetState(table_, listener_id_));
     263        3043 :     if (state) {
     264        1686 :         return state;
     265             :     } else {
     266        1357 :         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        3041 : ResolverNexthop *PathResolver::LocateResolverNexthop(IpAddress address,
     277             :     BgpTable *table) {
     278        3041 :     CHECK_CONCURRENCY("db::DBTable", "bgp::RouteAggregation",
     279             :                       "bgp::Config", "bgp::ConfigHelper");
     280             : 
     281        3043 :     std::scoped_lock lock(mutex_);
     282        3043 :     ResolverNexthopKey key(address, table);
     283        3043 :     ResolverNexthopMap::iterator loc = nexthop_map_.find(key);
     284        3043 :     if (loc != nexthop_map_.end()) {
     285        1852 :         return loc->second;
     286             :     } else {
     287        1191 :         ResolverNexthop *rnexthop = new ResolverNexthop(this, address, table);
     288        1191 :         nexthop_map_.insert(make_pair(key, rnexthop));
     289        1191 :         return rnexthop;
     290             :     }
     291        3043 : }
     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        1191 : void PathResolver::RemoveResolverNexthop(ResolverNexthop *rnexthop) {
     307        1191 :     CHECK_CONCURRENCY("bgp::Config");
     308             : 
     309        1191 :     ResolverNexthopKey key(rnexthop->address(), rnexthop->table());
     310        1191 :     ResolverNexthopMap::iterator loc = nexthop_map_.find(key);
     311        1191 :     assert(loc != nexthop_map_.end());
     312        1191 :     nexthop_map_.erase(loc);
     313        1191 :     nexthop_update_list_.erase(rnexthop);
     314        1191 : }
     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        1175 : void PathResolver::UnregisterResolverNexthopDone(BgpTable *table,
     325             :     ConditionMatch *match) {
     326        1175 :     CHECK_CONCURRENCY("db::Walker");
     327             : 
     328        1175 :     ResolverNexthop *rnexthop = dynamic_cast<ResolverNexthop *>(match);
     329        1175 :     assert(rnexthop);
     330        1175 :     assert(rnexthop->registered());
     331        1175 :     assert(rnexthop->deleted());
     332        1175 :     assert(nexthop_delete_list_.find(rnexthop) != nexthop_delete_list_.end());
     333        1175 :     RegisterUnregisterResolverNexthop(rnexthop);
     334        1175 : }
     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        4159 : bool PathResolver::ProcessResolverNexthopRegUnreg(ResolverNexthop *rnexthop) {
     342        4159 :     CHECK_CONCURRENCY("bgp::Config");
     343             : 
     344        4159 :     BgpTable *table = rnexthop->table();
     345        4159 :     Address::Family family = table->family();
     346        4159 :     BgpConditionListener *condition_listener = get_condition_listener(family);
     347             : 
     348        4159 :     if (rnexthop->registered()) {
     349        2960 :         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        1175 :             nexthop_delete_list_.erase(rnexthop);
     355        1175 :             condition_listener->UnregisterMatchCondition(table, rnexthop);
     356        1785 :         } 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        1175 :             RemoveResolverNexthop(rnexthop);
     364        1175 :             nexthop_delete_list_.insert(rnexthop);
     365             :             BgpConditionListener::RequestDoneCb cb = boost::bind(
     366        1175 :                 &PathResolver::UnregisterResolverNexthopDone, this, _1, _2);
     367        1175 :             condition_listener->RemoveMatchCondition(table, rnexthop, cb);
     368        1175 :         }
     369             :     } else {
     370        1199 :         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        1183 :             if (!table->IsDeleted()) {
     376        1175 :                 condition_listener->AddMatchCondition(
     377        2350 :                     table, rnexthop, BgpConditionListener::RequestDoneCb());
     378        1175 :                 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          16 :             RemoveResolverNexthop(rnexthop);
     391          16 :             return true;
     392             :         }
     393             :     }
     394             : 
     395        4143 :     return false;
     396             : }
     397             : 
     398             : //
     399             : // Handle processing of all ResolverNexthops on the register/unregister list.
     400             : //
     401        3710 : bool PathResolver::ProcessResolverNexthopRegUnregList() {
     402        3710 :     CHECK_CONCURRENCY("bgp::Config");
     403             : 
     404        3710 :     for (ResolverNexthopList::iterator it = nexthop_reg_unreg_list_.begin();
     405        7869 :          it != nexthop_reg_unreg_list_.end(); ++it) {
     406        4159 :         ResolverNexthop *rnexthop = *it;
     407        4159 :         if (ProcessResolverNexthopRegUnreg(rnexthop))
     408          16 :             delete rnexthop;
     409             :     }
     410        3710 :     nexthop_reg_unreg_list_.clear();
     411             : 
     412        3710 :     RetryDelete();
     413        3710 :     return true;
     414             : }
     415             : 
     416             : //
     417             : // Handle processing of all ResolverNexthops on the update list.
     418             : //
     419        3577 : bool PathResolver::ProcessResolverNexthopUpdateList() {
     420        3577 :     CHECK_CONCURRENCY("bgp::ResolverNexthop");
     421             : 
     422        3577 :     for (ResolverNexthopList::iterator it = nexthop_update_list_.begin();
     423        8551 :          it != nexthop_update_list_.end(); ++it) {
     424        4974 :         ResolverNexthop *rnexthop = *it;
     425        4974 :         assert(!rnexthop->deleted());
     426        4974 :         rnexthop->TriggerAllResolverPaths();
     427             :     }
     428        3577 :     nexthop_update_list_.clear();
     429        3577 :     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      171624 : void PathResolver::ManagedDelete() {
     443      171624 :     deleter_->Delete();
     444      171624 : }
     445             : 
     446             : //
     447             : // Return true if it's safe to delete the PathResolver.
     448             : //
     449      171730 : bool PathResolver::MayDelete() const {
     450      171730 :     if (!nexthop_map_.empty())
     451          33 :         return false;
     452      171697 :     if (!nexthop_delete_list_.empty())
     453          73 :         return false;
     454      171624 :     if (!nexthop_reg_unreg_list_.empty())
     455           0 :         return false;
     456      171624 :     assert(nexthop_update_list_.empty());
     457      171624 :     return true;
     458             : }
     459             : 
     460             : //
     461             : // Attempt to enqueue a delete for the PathResolver.
     462             : //
     463        3710 : void PathResolver::RetryDelete() {
     464        3710 :     if (!deleter_->IsDeleted())
     465        3593 :         return;
     466         117 :     deleter_->RetryDelete();
     467             : }
     468             : 
     469             : //
     470             : // Dummy callback - required in order to get a listener_id for use with
     471             : // BgpConditionListener.
     472             : //
     473     1240061 : bool PathResolver::RouteListener(DBTablePartBase *root, DBEntryBase *entry) {
     474     1240061 :     return true;
     475             : }
     476             : 
     477             : //
     478             : // Get size of the map.
     479             : // For testing only.
     480             : //
     481          32 : size_t PathResolver::GetResolverNexthopMapSize() const {
     482          32 :     std::scoped_lock lock(mutex_);
     483          64 :     return nexthop_map_.size();
     484          32 : }
     485             : 
     486             : //
     487             : // Get size of the delete list.
     488             : // For testing only.
     489             : //
     490          20 : size_t PathResolver::GetResolverNexthopDeleteListSize() const {
     491          20 :     std::scoped_lock lock(mutex_);
     492          40 :     return nexthop_delete_list_.size();
     493          20 : }
     494             : 
     495             : //
     496             : // Disable processing of the register/unregister list.
     497             : // For testing only.
     498             : //
     499          16 : void PathResolver::DisableResolverNexthopRegUnregProcessing() {
     500          16 :     nexthop_reg_unreg_trigger_->set_disable();
     501          16 : }
     502             : 
     503             : //
     504             : // Enable processing of the register/unregister list.
     505             : // For testing only.
     506             : //
     507          16 : void PathResolver::EnableResolverNexthopRegUnregProcessing() {
     508          16 :     nexthop_reg_unreg_trigger_->set_enable();
     509          16 : }
     510             : 
     511             : //
     512             : // Get size of the update list.
     513             : // For testing only.
     514             : //
     515          28 : size_t PathResolver::GetResolverNexthopRegUnregListSize() const {
     516          28 :     std::scoped_lock lock(mutex_);
     517          56 :     return nexthop_reg_unreg_list_.size();
     518          28 : }
     519             : 
     520             : //
     521             : // Disable processing of the update list.
     522             : // For testing only.
     523             : //
     524          16 : void PathResolver::DisableResolverNexthopUpdateProcessing() {
     525          16 :     nexthop_update_trigger_->set_disable();
     526          16 : }
     527             : 
     528             : //
     529             : // Enable processing of the update list.
     530             : // For testing only.
     531             : //
     532          16 : void PathResolver::EnableResolverNexthopUpdateProcessing() {
     533          16 :     nexthop_update_trigger_->set_enable();
     534          16 : }
     535             : 
     536             : //
     537             : // Get size of the update list.
     538             : // For testing only.
     539             : //
     540          56 : size_t PathResolver::GetResolverNexthopUpdateListSize() const {
     541          56 :     std::scoped_lock lock(mutex_);
     542         112 :     return nexthop_update_list_.size();
     543          56 : }
     544             : 
     545             : //
     546             : // Disable processing of the path update list in all partitions.
     547             : // For testing only.
     548             : //
     549          16 : void PathResolver::DisableResolverPathUpdateProcessing() {
     550          80 :     for (int part_id = 0; part_id < DB::PartitionCount(); ++part_id) {
     551          64 :         partitions_[part_id]->DisableResolverPathUpdateProcessing();
     552             :     }
     553          16 : }
     554             : 
     555             : //
     556             : // Enable processing of the path update list in all partitions.
     557             : // For testing only.
     558             : //
     559          16 : void PathResolver::EnableResolverPathUpdateProcessing() {
     560          80 :     for (int part_id = 0; part_id < DB::PartitionCount(); ++part_id) {
     561          64 :         partitions_[part_id]->EnableResolverPathUpdateProcessing();
     562             :     }
     563          16 : }
     564             : 
     565             : //
     566             : // Pause processing of the path update list in all partitions.
     567             : // For testing only.
     568             : //
     569           4 : void PathResolver::PauseResolverPathUpdateProcessing() {
     570          20 :     for (int part_id = 0; part_id < DB::PartitionCount(); ++part_id) {
     571          16 :         partitions_[part_id]->PauseResolverPathUpdateProcessing();
     572             :     }
     573           4 : }
     574             : 
     575             : //
     576             : // Resume processing of the path update list in all partitions.
     577             : // For testing only.
     578             : //
     579           4 : void PathResolver::ResumeResolverPathUpdateProcessing() {
     580          20 :     for (int part_id = 0; part_id < DB::PartitionCount(); ++part_id) {
     581          16 :         partitions_[part_id]->ResumeResolverPathUpdateProcessing();
     582             :     }
     583           4 : }
     584             : 
     585             : //
     586             : // Get size of the update list.
     587             : // For testing only.
     588             : //
     589          72 : size_t PathResolver::GetResolverPathUpdateListSize() const {
     590          72 :     size_t total = 0;
     591         360 :     for (int part_id = 0; part_id < DB::PartitionCount(); ++part_id) {
     592         288 :         total += partitions_[part_id]->GetResolverPathUpdateListSize();
     593             :     }
     594          72 :     return total;
     595             : }
     596             : 
     597             : //
     598             : // Fill introspect information.
     599             : //
     600          64 : void PathResolver::FillShowInfo(ShowPathResolver *spr, bool summary) const {
     601          64 :     spr->set_name(table_->name());
     602             : 
     603          64 :     size_t path_count = 0;
     604          64 :     size_t modified_path_count = 0;
     605          64 :     vector<ShowPathResolverPath> sprp_list;
     606         320 :     for (int part_id = 0; part_id < DB::PartitionCount(); ++part_id) {
     607         256 :         const PathResolverPartition *partition = partitions_[part_id];
     608         256 :         path_count += partition->rpath_map_.size();
     609         256 :         modified_path_count += partition->rpath_update_list_.size();
     610         256 :         if (summary)
     611         128 :             continue;
     612         128 :         for (PathResolverPartition::PathToResolverPathMap::const_iterator it =
     613         352 :              partition->rpath_map_.begin(); it != partition->rpath_map_.end();
     614          96 :              ++it) {
     615          96 :             const ResolverPath *rpath = it->second;
     616          96 :             ShowPathResolverPath sprp;
     617          96 :             sprp.set_prefix(rpath->route()->ToString());
     618          96 :             sprp.set_nexthop(rpath->rnexthop()->address().to_string());
     619          96 :             sprp.set_resolved_path_count(rpath->resolved_path_count());
     620          96 :             sprp_list.push_back(sprp);
     621          96 :         }
     622             :     }
     623          64 :     spr->set_path_count(path_count);
     624          64 :     spr->set_modified_path_count(modified_path_count);
     625          64 :     spr->set_nexthop_count(nexthop_map_.size());
     626         128 :     spr->set_modified_nexthop_count(nexthop_reg_unreg_list_.size() +
     627          64 :         nexthop_delete_list_.size() + nexthop_update_list_.size());
     628             : 
     629          64 :     if (summary)
     630          32 :         return;
     631             : 
     632          32 :     vector<ShowPathResolverNexthop> sprn_list;
     633          32 :     for (ResolverNexthopMap::const_iterator it = nexthop_map_.begin();
     634          44 :          it != nexthop_map_.end(); ++it) {
     635          12 :         const ResolverNexthop *rnexthop = it->second;
     636          12 :         const BgpTable *table = rnexthop->table();
     637          12 :         ShowPathResolverNexthop sprn;
     638          12 :         sprn.set_address(rnexthop->address().to_string());
     639          12 :         sprn.set_table(table->name());
     640          12 :         const BgpRoute *route = rnexthop->GetRoute();
     641          12 :         if (route) {
     642          12 :             ShowRouteBrief show_route;
     643          12 :             route->FillRouteInfo(table, &show_route);
     644          12 :             sprn.set_nexthop_route(show_route);
     645          12 :         }
     646          12 :         sprn_list.push_back(sprn);
     647          12 :     }
     648             : 
     649          32 :     spr->set_paths(sprp_list);
     650          32 :     spr->set_nexthops(sprn_list);
     651          64 : }
     652             : 
     653             : //
     654             : //
     655             : // Constructor for PathResolverPartition.
     656             : // A new PathResolverPartition is created when a PathResolver is created.
     657             : //
     658      683549 : PathResolverPartition::PathResolverPartition(int part_id,
     659      683549 :     PathResolver *resolver)
     660      683549 :     : part_id_(part_id),
     661      683549 :       resolver_(resolver),
     662     1367058 :       rpath_update_trigger_(new TaskTrigger(
     663             :           boost::bind(&PathResolverPartition::ProcessResolverPathUpdateList,
     664             :               this),
     665     1366961 :           TaskScheduler::GetInstance()->GetTaskId("bgp::ResolverPath"),
     666     1367256 :           part_id)) {
     667      683540 : }
     668             : 
     669             : //
     670             : // Destructor for PathResolverPartition.
     671             : // All PathResolverPartitions for a PathResolver are destroyed when the
     672             : // PathResolver is destroyed.
     673             : //
     674      683748 : PathResolverPartition::~PathResolverPartition() {
     675      683748 :     assert(rpath_update_list_.empty());
     676      683748 :     rpath_update_trigger_->Reset();
     677      683748 : }
     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        3051 : void PathResolverPartition::StartPathResolution(BgpRoute *route,
     688             :         const BgpPath *path, BgpTable *nh_table) {
     689        3051 :     if (!path->IsResolutionFeasible())
     690          10 :         return;
     691        3045 :     if (table()->IsDeleted() || nh_table->IsDeleted())
     692           0 :         return;
     693             : 
     694        3047 :     Address::Family family = table()->family();
     695        3047 :     IpAddress address = path->GetAttr()->nexthop();
     696        3047 :     if (table() == nh_table && RoutePrefixIsAddress(family, route, address))
     697           4 :         return;
     698             : 
     699             :     ResolverNexthop *rnexthop;
     700        3041 :     if (family != Address::EVPN) {
     701        2341 :         rnexthop = resolver_->LocateResolverNexthop(address, nh_table);
     702             :     }
     703             :     else {
     704         700 :         rnexthop = resolver_->LocateResolverNexthop(address, table());
     705             :     }
     706        3043 :     assert(!FindResolverPath(path));
     707        3043 :     ResolverPath *rpath = CreateResolverPath(path, route, rnexthop);
     708        3043 :     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        3053 : void PathResolverPartition::StopPathResolution(const BgpPath *path) {
     717        3053 :     ResolverPath *rpath = RemoveResolverPath(path);
     718        3052 :     if (!rpath)
     719          10 :         return;
     720        3042 :     TriggerPathResolution(rpath);
     721             : }
     722             : 
     723             : //
     724             : // Add a ResolverPath to the update list and start Task to process the list.
     725             : //
     726       11950 : void PathResolverPartition::TriggerPathResolution(ResolverPath *rpath) {
     727       11950 :     CHECK_CONCURRENCY("db::DBTable", "bgp::ResolverNexthop",
     728             :         "bgp::Config", "bgp::ConfigHelper", "bgp::RouteAggregation");
     729             : 
     730       11951 :     rpath_update_list_.insert(rpath);
     731       11951 :     rpath_update_trigger_->Set();
     732       11951 : }
     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        6810 : DBTablePartBase *PathResolverPartition::table_partition() {
     750        6810 :     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        3043 : ResolverPath *PathResolverPartition::CreateResolverPath(const BgpPath *path,
     758             :     BgpRoute *route, ResolverNexthop *rnexthop) {
     759        3043 :     ResolverPath *rpath = new ResolverPath(this, path, route, rnexthop);
     760        3043 :     rpath_map_.insert(make_pair(path, rpath));
     761        3043 :     return rpath;
     762             : }
     763             : 
     764             : //
     765             : // Find the ResolverPath for given BgpPath.
     766             : //
     767        3043 : ResolverPath *PathResolverPartition::FindResolverPath(const BgpPath *path) {
     768        3043 :     PathToResolverPathMap::iterator loc = rpath_map_.find(path);
     769        3043 :     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        3053 : ResolverPath *PathResolverPartition::RemoveResolverPath(const BgpPath *path) {
     779        3053 :     PathToResolverPathMap::iterator loc = rpath_map_.find(path);
     780        3052 :     if (loc == rpath_map_.end()) {
     781          10 :         return NULL;
     782             :     } else {
     783        3042 :         ResolverPath *rpath = loc->second;
     784        3043 :         rpath_map_.erase(loc);
     785        3043 :         rpath->clear_path();
     786        3042 :         return rpath;
     787             :     }
     788             : }
     789             : 
     790             : //
     791             : // Handle processing of all ResolverPaths on the update list.
     792             : //
     793        8782 : bool PathResolverPartition::ProcessResolverPathUpdateList() {
     794        8782 :     CHECK_CONCURRENCY("bgp::ResolverPath");
     795             : 
     796        8775 :     ResolverPathList update_list;
     797        8773 :     rpath_update_list_.swap(update_list);
     798        8771 :     for (ResolverPathList::iterator it = update_list.begin();
     799       20565 :          it != update_list.end(); ++it) {
     800       11779 :         ResolverPath *rpath = *it;
     801       11779 :         if (rpath->UpdateResolvedPaths())
     802        3043 :             delete rpath;
     803             :     }
     804             : 
     805       17573 :     return rpath_update_list_.empty();
     806        8787 : }
     807             : 
     808             : //
     809             : // Disable processing of the update list.
     810             : // For testing only.
     811             : //
     812          64 : void PathResolverPartition::DisableResolverPathUpdateProcessing() {
     813          64 :     rpath_update_trigger_->set_disable();
     814          64 : }
     815             : 
     816             : //
     817             : // Enable processing of the update list.
     818             : // For testing only.
     819             : //
     820          64 : void PathResolverPartition::EnableResolverPathUpdateProcessing() {
     821          64 :     rpath_update_trigger_->set_enable();
     822          64 : }
     823             : 
     824             : //
     825             : // Pause processing of the update list.
     826             : // For testing only.
     827             : //
     828          16 : void PathResolverPartition::PauseResolverPathUpdateProcessing() {
     829          16 :     rpath_update_trigger_->set_deferred();
     830          16 : }
     831             : 
     832             : //
     833             : // Resume processing of the update list.
     834             : // For testing only.
     835             : //
     836          16 : void PathResolverPartition::ResumeResolverPathUpdateProcessing() {
     837          16 :     rpath_update_trigger_->clear_deferred();
     838          16 : }
     839             : 
     840             : //
     841             : // Get size of the update list.
     842             : // For testing only.
     843             : //
     844         288 : size_t PathResolverPartition::GetResolverPathUpdateListSize() const {
     845         288 :     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        1357 : ResolverRouteState::ResolverRouteState(PathResolver *resolver,
     855        1357 :     BgpRoute *route)
     856        1357 :     : resolver_(resolver),
     857        1357 :       route_(route),
     858        1357 :       refcount_(0) {
     859        1357 :     route_->SetState(resolver_->table(), resolver_->listener_id(), this);
     860        1357 : }
     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        2714 : ResolverRouteState::~ResolverRouteState() {
     870        1357 :     route_->ClearState(resolver_->table(), resolver_->listener_id());
     871        2714 : }
     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        3043 : ResolverPath::ResolverPath(PathResolverPartition *partition,
     881        3043 :     const BgpPath *path, BgpRoute *route, ResolverNexthop *rnexthop)
     882        3043 :     : partition_(partition),
     883        3043 :       path_(path),
     884        3043 :       route_(route),
     885        3043 :       rnexthop_(rnexthop),
     886        3043 :       state_(partition_->resolver()->LocateResolverRouteState(route)) {
     887        3043 :     rnexthop->AddResolverPath(partition->part_id(), this);
     888        3043 : }
     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        3043 : ResolverPath::~ResolverPath() {
     900        3043 :     rnexthop_->RemoveResolverPath(partition_->part_id(), this);
     901        3043 : }
     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        2996 : void ResolverPath::AddResolvedPath(ResolvedPathList::const_iterator it) {
     908        2996 :     BgpPath *path = *it;
     909        2996 :     const IPeer *peer = path->GetPeer();
     910        2996 :     resolved_path_list_.insert(path);
     911        2996 :     route_->InsertPath(path);
     912        2996 :     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        2996 : }
     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        2995 : void ResolverPath::DeleteResolvedPath(ResolvedPathList::const_iterator it) {
     926        2995 :     BgpPath *path = *it;
     927        2996 :     const IPeer *peer = path->GetPeer();
     928        2996 :     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        2996 :     route_->DeletePath(path);
     936        2996 :     resolved_path_list_.erase(it);
     937        2996 : }
     938             : 
     939             : //
     940             : // Find or create the matching resolved BgpPath.
     941             : //
     942        6304 : BgpPath *ResolverPath::LocateResolvedPath(const IPeer *peer, uint32_t path_id,
     943             :     const BgpAttr *attr, uint32_t label, bool is_replicated) {
     944        6304 :     for (ResolvedPathList::iterator it = resolved_path_list_.begin();
     945        6489 :          it != resolved_path_list_.end(); ++it) {
     946        3493 :         BgpPath *path = *it;
     947        6986 :         if (path->GetPeer() == peer &&
     948        6893 :             path->GetPathId() == path_id &&
     949       10386 :             path->GetAttr() == attr &&
     950        3368 :             path->GetLabel() == label) {
     951        3308 :             return path;
     952             :         }
     953             :     }
     954             : 
     955        2996 :     BgpPath::PathSource src = path_->GetSource();
     956             :     uint32_t flags =
     957        2996 :         (path_->GetFlags() & ~BgpPath::ResolveNexthop) | BgpPath::ResolvedPath;
     958        2996 :     if (is_replicated) {
     959           0 :         return (new BgpSecondaryPath(peer, path_id, src, attr, flags, label));
     960             :     } else {
     961        2996 :         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        6197 : static ExtCommunityPtr UpdateExtendedCommunity(ExtCommunityDB *extcomm_db,
     973             :     const BgpAttr *attr, const BgpAttr *nh_attr) {
     974        6197 :     ExtCommunityPtr ext_community = attr->ext_community();
     975        6198 :     const ExtCommunity *nh_ext_community = nh_attr->ext_community();
     976        6198 :     if (!nh_ext_community)
     977         903 :         return ext_community;
     978             : 
     979        5295 :     ExtCommunity::ExtCommunityList rtarget;
     980        5295 :     ExtCommunity::ExtCommunityList sgid_list;
     981        5295 :     ExtCommunity::ExtCommunityList encap_list;
     982        5295 :     ExtCommunity::ExtCommunityValue const *source_as = NULL;
     983        5295 :     ExtCommunity::ExtCommunityValue const *lb = NULL;
     984        5295 :     ExtCommunity::ExtCommunityValue const *rt_mac = nullptr;
     985       32571 :     BOOST_FOREACH(const ExtCommunity::ExtCommunityValue &value,
     986             :         nh_ext_community->communities()) {
     987       21973 :         if (ExtCommunity::is_security_group(value) ||
     988        8335 :                 ExtCommunity::is_security_group4(value)) {
     989        5303 :             sgid_list.push_back(value);
     990        8335 :         } else if (ExtCommunity::is_tunnel_encap(value)) {
     991        6585 :             encap_list.push_back(value);
     992        1750 :         } else if (ExtCommunity::is_vrf_route_import(value)) {
     993         110 :             VrfRouteImport vit(value);
     994         220 :             rtarget.push_back(RouteTarget(vit.GetIPv4Address(),
     995         220 :                                           vit.GetNumber()).GetExtCommunity());
     996        1640 :         } else if (ExtCommunity::is_source_as(value)) {
     997         110 :             source_as = &value;
     998        1530 :         } else if (ExtCommunity::is_load_balance(value) && !lb) {
     999           8 :             lb = &value;
    1000        1522 :         } 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       10590 :     ext_community = extcomm_db->ReplaceRTargetAndLocate(ext_community.get(),
    1007        5295 :                                                         rtarget);
    1008       10590 :     ext_community = extcomm_db->ReplaceSGIDListAndLocate(
    1009        5295 :         ext_community.get(), sgid_list);
    1010       10590 :     ext_community = extcomm_db->ReplaceTunnelEncapsulationAndLocate(
    1011        5295 :         ext_community.get(), encap_list);
    1012        5295 :     if (source_as) {
    1013         220 :         ext_community = extcomm_db->ReplaceSourceASAndLocate(
    1014         110 :                 ext_community.get(), *source_as);
    1015             :     }
    1016        5295 :     if (lb) {
    1017          16 :         ext_community = extcomm_db->ReplaceLoadBalanceAndLocate(
    1018           8 :             ext_community.get(), *lb);
    1019             :     }
    1020        5295 :     if (rt_mac) {
    1021           0 :         ext_community = extcomm_db->AppendAndLocate(
    1022           0 :             ext_community.get(), *rt_mac);
    1023             :     }
    1024        5295 :     return ext_community;
    1025        5295 : }
    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       11778 : bool ResolverPath::UpdateResolvedPaths() {
    1038       11778 :     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       11784 :     tbb::spin_rw_mutex::scoped_lock rt_write_lock;
    1043       11783 :     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       11794 :     tbb::spin_rw_mutex::scoped_lock nh_read_lock;
    1052       11794 :     ResolverRouteState *nh_state = rnexthop_->GetResolverRouteState();
    1053       23588 :     if (state_ != nh_state &&
    1054       23588 :         nh_state && !nh_read_lock.try_acquire(nh_state->rw_mutex(), false)) {
    1055           0 :         partition_->DeferPathResolution(this);
    1056           0 :         return false;
    1057             :     }
    1058             : 
    1059       11794 :     BgpServer *server = partition_->table()->server();
    1060       11790 :     BgpAttrDB *attr_db = server->attr_db();
    1061       11787 :     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       11784 :     ResolvedPathList future_resolved_path_list;
    1069       11784 :     const BgpRoute *nh_route = rnexthop_->GetRoute();
    1070       11792 :     const IPeer *peer = path_ ? path_->GetPeer() : NULL;
    1071             :     // Process paths of nexthop route if nexthop RI is not the master RI.
    1072       11793 :     const RoutingInstance *nh_ri = rnexthop_->table()->routing_instance();
    1073       11793 :     bool nh_ri_def = false;
    1074       11793 :     if (nh_ri->IsMasterRoutingInstance()) {
    1075         320 :         nh_ri_def = true;
    1076             :     }
    1077       11793 :     bool process_paths = false;
    1078       11793 :     if (path_ && nh_route && !nh_ri_def) {
    1079        6135 :         process_paths = true;
    1080             :     }
    1081             :     Route::PathList::const_iterator it;
    1082       11793 :     if (process_paths)
    1083       12266 :         it = nh_route->GetPathList().begin();
    1084       30330 :     for (; process_paths && it != nh_route->GetPathList().end(); ++it) {
    1085        6229 :         const BgpPath *nh_path = static_cast<const BgpPath *>(it.operator->());
    1086             : 
    1087             :         // Start with attributes of the original path.
    1088        6229 :         BgpAttrPtr attr(path_->GetAttr());
    1089             : 
    1090             :         // Infeasible nexthop paths are not considered.
    1091        6237 :         if (!nh_path->IsFeasible())
    1092          32 :             break;
    1093             : 
    1094             :         // Take snapshot of all ECMP nexthop paths.
    1095        6205 :         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        6179 :         if (nh_route->DuplicateForwardingPath(nh_path))
    1103           8 :             continue;
    1104             : 
    1105             :         // Skip if there's no source rd.
    1106        6172 :         RouteDistinguisher source_rd = nh_path->GetSourceRouteDistinguisher();
    1107        6167 :         if (source_rd.IsZero())
    1108           0 :             continue;
    1109             : 
    1110             :         // Use source rd from the nexthop path.
    1111        6183 :         attr = attr_db->ReplaceSourceRdAndLocate(attr.get(), source_rd);
    1112             : 
    1113             :         // Use nexthop address from the nexthop path.
    1114       12396 :         attr = attr_db->ReplaceNexthopAndLocate(attr.get(),
    1115        6198 :             nh_path->GetAttr()->nexthop());
    1116             : 
    1117             :         // obtain  extcommunities from original attrs and allow
    1118             :         // route target type values.
    1119        6198 :         ExtCommunityPtr ext_community = attr->ext_community();
    1120        6198 :         ExtCommunity::ExtCommunityList export_list;
    1121        6198 :         if (ext_community)
    1122             :         {
    1123         545 :             BOOST_FOREACH(const ExtCommunity::ExtCommunityValue &v,
    1124             :                ext_community->communities()) {
    1125         183 :                if (!ExtCommunity::is_route_target(v))
    1126         175 :                   continue;
    1127           8 :                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        6198 :             UpdateExtendedCommunity(extcomm_db, attr.get(), nh_path->GetAttr());
    1134        6198 :         if (!export_list.empty()) {
    1135           4 :             ext_community = extcomm_db->AppendAndLocate(ext_community.get(), export_list);
    1136             :         }
    1137        6198 :         attr = attr_db->ReplaceExtCommunityAndLocate(attr.get(), ext_community);
    1138             : 
    1139             :         // Locate the resolved path.
    1140        6198 :         uint32_t path_id = nh_path->GetAttr()->nexthop().to_v4().to_ulong();
    1141             :         BgpPath *resolved_path =
    1142        6198 :             LocateResolvedPath(peer, path_id, attr.get(), nh_path->GetLabel());
    1143        6198 :         future_resolved_path_list.insert(resolved_path);
    1144        6238 :     }
    1145             : 
    1146             :     // If nexthop RI is the default routing-instance, nothing to update except
    1147             :     // changing path_flags. Locate the resolved path.
    1148       11796 :     if (path_ && nh_route && nh_ri_def) {
    1149         106 :         BgpPath *updated_path = LocateResolvedPath(peer, path_->GetPathId(),
    1150         106 :             path_->GetAttr(), path_->GetLabel(), path_->IsReplicated());
    1151         106 :         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         106 :         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       11796 :     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       11794 :     if (route_->HasPaths()) {
    1169       10411 :         if (modified) {
    1170        5427 :             partition_->table_partition()->Notify(route_);
    1171             :         }
    1172             :     } else {
    1173        1383 :         partition_->table_partition()->Delete(route_);
    1174             :     }
    1175             : 
    1176       11794 :     return (!path_);
    1177       11794 : }
    1178             : 
    1179             : //
    1180             : // Constructor for ResolverNexthop.
    1181             : // Initialize the vector of paths_lists to the number of DB partitions.
    1182             : //
    1183        1197 : ResolverNexthop::ResolverNexthop(PathResolver *resolver, IpAddress address,
    1184        1197 :     BgpTable *table)
    1185        1197 :     : resolver_(resolver),
    1186        1197 :       address_(address),
    1187        1197 :       table_(table),
    1188        1197 :       registered_(false),
    1189        1197 :       rpath_lists_(DB::PartitionCount()),
    1190        3591 :       table_delete_ref_(this, table->deleter()) {
    1191        1197 : }
    1192             : 
    1193             : //
    1194             : // Destructor for ResolverNexthop.
    1195             : // A deep delete of the path_lists vector is not required.
    1196             : //
    1197        2388 : ResolverNexthop::~ResolverNexthop() {
    1198        1197 :     assert(routes_.empty());
    1199        2388 : }
    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       51444 : bool ResolverNexthop::Match(BgpServer *server, BgpTable *table,
    1212             :     BgpRoute *route, bool deleted) {
    1213       51444 :     CHECK_CONCURRENCY("db::DBTable");
    1214             : 
    1215             :     // Ignore if the route doesn't match the address.
    1216       51451 :     Address::Family family = table->family();
    1217       51448 :     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       51448 :     if (!resolver_->nexthop_longest_match()) {
    1222       51196 :         if (!RoutePrefixIsAddress(family, route, address_))
    1223       46026 :             return false;
    1224             :     } else {
    1225         254 :         if (!resolver_->RoutePrefixMatch(route, address_))
    1226          28 :             return false;
    1227             :     }
    1228             : 
    1229             :     // Do not resolve over self.
    1230       10075 :     if (route->table() == table && route->IsUsable() &&
    1231        4686 :             route->BestPath()->GetAttr()->nexthop() == address_) {
    1232           4 :         return false;
    1233             :     }
    1234             : 
    1235             :     // Set or remove MatchState as appropriate.
    1236             :     BgpConditionListener *condition_listener =
    1237        5438 :         resolver_->get_condition_listener(family);
    1238        5437 :     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        5439 :     bool longest_match_updated = true;
    1244        5439 :     if (deleted) {
    1245        1159 :         if (state_added) {
    1246        1123 :             longest_match_updated = RemoveRoute(route);
    1247        1123 :             condition_listener->RemoveMatchState(table, route, this);
    1248             :         } else {
    1249          36 :             return false;
    1250             :         }
    1251             :     } else {
    1252        4280 :         if (!state_added) {
    1253        1123 :             longest_match_updated = InsertRoute(route);
    1254        1123 :             condition_listener->SetMatchState(table, route, this);
    1255             :         }
    1256             :     }
    1257             : 
    1258             :     // Nothing more to do if the ConditionMatch has been removed.
    1259        5403 :     if (ConditionMatch::deleted())
    1260         406 :         return false;
    1261             : 
    1262             :     // Trigger re-evaluation of all dependent ResolverPaths if the longest
    1263             :     // matching route was updated.
    1264        4997 :     if (longest_match_updated)
    1265        4997 :         resolver_->UpdateResolverNexthop(this);
    1266        4997 :     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        3043 : void ResolverNexthop::AddResolverPath(int part_id, ResolverPath *rpath) {
    1281        3043 :     CHECK_CONCURRENCY("db::DBTable", "bgp::RouteAggregation",
    1282             :         "bgp::Config", "bgp::ConfigHelper");
    1283             : 
    1284        3043 :     if (rpath_lists_[part_id].empty())
    1285        1504 :         resolver_->RegisterUnregisterResolverNexthop(this);
    1286        3043 :     rpath_lists_[part_id].insert(rpath);
    1287        3043 : }
    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        3043 : void ResolverNexthop::RemoveResolverPath(int part_id, ResolverPath *rpath) {
    1301        3043 :     CHECK_CONCURRENCY("bgp::ResolverPath");
    1302             : 
    1303        3043 :     rpath_lists_[part_id].erase(rpath);
    1304        3043 :     if (rpath_lists_[part_id].empty())
    1305        1504 :         resolver_->RegisterUnregisterResolverNexthop(this);
    1306        3043 : }
    1307             : 
    1308       11794 : ResolverRouteState *ResolverNexthop::GetResolverRouteState() {
    1309       11794 :     if (!GetRoute())
    1310        3703 :         return NULL;
    1311        8089 :     PathResolver *nh_resolver = table_->path_resolver();
    1312        8087 :     if (!nh_resolver)
    1313         138 :         return NULL;
    1314        7949 :     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        4974 : void ResolverNexthop::TriggerAllResolverPaths() const {
    1323        4974 :     CHECK_CONCURRENCY("bgp::ResolverNexthop");
    1324             : 
    1325       24858 :     for (int part_id = 0; part_id < DB::PartitionCount(); ++part_id) {
    1326       19884 :         for (ResolverPathList::iterator it = rpath_lists_[part_id].begin();
    1327       25749 :              it != rpath_lists_[part_id].end(); ++it) {
    1328        5865 :             ResolverPath *rpath = *it;
    1329        5865 :             resolver_->GetPartition(part_id)->TriggerPathResolution(rpath);
    1330             :         }
    1331             :     }
    1332        4974 : }
    1333             : 
    1334             : //
    1335             : // Return true if there are no dependent ResolverPaths in all partitions.
    1336             : //
    1337        2984 : bool ResolverNexthop::empty() const {
    1338        2984 :     CHECK_CONCURRENCY("bgp::Config");
    1339             : 
    1340        9472 :     for (int part_id = 0; part_id < DB::PartitionCount(); ++part_id) {
    1341        8281 :         if (!rpath_lists_[part_id].empty())
    1342        1793 :             return false;
    1343             :     }
    1344        1191 :     return true;
    1345             : }
    1346             : 
    1347        2440 : bool ResolverNexthop::ResolverRouteCompare::operator()(
    1348             :         const BgpRoute *lhs, const BgpRoute *rhs) const {
    1349        2440 :     const InetRoute *lhs4 = dynamic_cast<const InetRoute *>(lhs);
    1350        2440 :     const InetRoute *rhs4 = dynamic_cast<const InetRoute *>(rhs);
    1351        2440 :     if (lhs4) {
    1352        1772 :         return lhs4->GetPrefix().prefixlen() > rhs4->GetPrefix().prefixlen();
    1353             :     }
    1354             : 
    1355         668 :     const Inet6Route *lhs6 = dynamic_cast<const Inet6Route *>(lhs);
    1356         668 :     const Inet6Route *rhs6 = dynamic_cast<const Inet6Route *>(rhs);
    1357         668 :     if (lhs6) {
    1358         348 :         return lhs6->GetPrefix().prefixlen() > rhs6->GetPrefix().prefixlen();
    1359             :     }
    1360             : 
    1361         320 :     const EvpnRoute *lhs_e = dynamic_cast<const EvpnRoute *>(lhs);
    1362         320 :     const EvpnRoute *rhs_e = dynamic_cast<const EvpnRoute *>(rhs);
    1363         320 :     if (lhs_e != nullptr) {
    1364         320 :         return lhs_e->GetPrefix().ip_address_length() >
    1365         320 :             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        1123 : bool ResolverNexthop::InsertRoute(BgpRoute *route) {
    1375        1123 :     std::scoped_lock lock(routes_mutex_);
    1376        1123 :     routes_.insert(route);
    1377        1123 :     bool longest_match = (*(routes_.begin()) == route);
    1378        1123 :     return longest_match;
    1379        1123 : }
    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        1123 : bool ResolverNexthop::RemoveRoute(BgpRoute *route) {
    1384        1123 :     std::scoped_lock lock(routes_mutex_);
    1385        1123 :     bool longest_match = (*(routes_.begin()) == route);
    1386        1123 :     routes_.erase(route);
    1387        1123 :     return longest_match;
    1388        1123 : }
    1389             : 
    1390          12 : const BgpRoute *ResolverNexthop::GetRoute() const {
    1391          12 :     std::scoped_lock lock(routes_mutex_);
    1392          24 :     return !routes_.empty() ? *(routes_.begin()) : NULL;
    1393          12 : }
    1394             : 
    1395       31522 : BgpRoute *ResolverNexthop::GetRoute() {
    1396       31522 :     std::scoped_lock lock(routes_mutex_);
    1397       63073 :     return !routes_.empty() ? *(routes_.begin()) : NULL;
    1398       31526 : }

Generated by: LCOV version 1.14