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 52367 : static bool RoutePrefixIsAddress(Address::Family family, const BgpRoute *route,
33 : const IpAddress &address) {
34 52367 : if (family == Address::INET) {
35 38171 : const InetRoute *inet_route = static_cast<const InetRoute *>(route);
36 42327 : if (inet_route->GetPrefix().addr() == address.to_v4() &&
37 4129 : inet_route->GetPrefix().prefixlen() == Address::kMaxV4PrefixLen) {
38 4129 : return true;
39 : }
40 14196 : } else if (family == Address::INET6) {
41 1419 : const Inet6Route *inet6_route = static_cast<const Inet6Route *>(route);
42 1743 : if (inet6_route->GetPrefix().addr() == address.to_v6() &&
43 324 : inet6_route->GetPrefix().prefixlen() == Address::kMaxV6PrefixLen) {
44 324 : return true;
45 : }
46 12777 : } else if (family == Address::EVPN) {
47 12778 : const EvpnRoute *evpn_route = static_cast<const EvpnRoute *>(route);
48 12778 : if (evpn_route->GetPrefix().family() == Address::INET && address.is_v4()) {
49 8781 : if (evpn_route->GetPrefix().addr().to_v4() == address.to_v4() &&
50 751 : evpn_route->GetPrefix().prefixlen() == Address::kMaxV4PrefixLen) {
51 751 : return true;
52 : }
53 9532 : } else if (evpn_route->GetPrefix().family() == Address::INET6 &&
54 4766 : 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 47200 : return false;
62 : }
63 :
64 : // Return true if prefix matches the address.
65 292 : bool PathResolver::RoutePrefixMatch(const BgpRoute *route,
66 : const IpAddress &address) {
67 292 : const InetRoute *inet_route = dynamic_cast<const InetRoute *>(route);
68 292 : if (inet_route) {
69 238 : Ip4Prefix prefix(address.to_v4(), Address::kMaxV4PrefixLen);
70 238 : 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 171607 : explicit DeleteActor(PathResolver *resolver)
97 171607 : : LifetimeActor(resolver->table()->server()->lifetime_manager()),
98 171607 : resolver_(resolver) {
99 171629 : }
100 343264 : virtual ~DeleteActor() {
101 343264 : }
102 :
103 171736 : virtual bool MayDelete() const {
104 171736 : return resolver_->MayDelete();
105 : }
106 :
107 171632 : virtual void Destroy() {
108 171632 : resolver_->table()->DestroyPathResolver();
109 171632 : }
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 171628 : PathResolver::PathResolver(BgpTable *table)
125 171628 : : table_(table),
126 171628 : listener_id_(table->Register(
127 : boost::bind(&PathResolver::RouteListener, this, _1, _2),
128 : "PathResolver")),
129 171615 : nexthop_longest_match_(false),
130 343221 : nexthop_reg_unreg_trigger_(new TaskTrigger(
131 : boost::bind(&PathResolver::ProcessResolverNexthopRegUnregList, this),
132 343220 : TaskScheduler::GetInstance()->GetTaskId("bgp::Config"),
133 171629 : 0)),
134 343219 : nexthop_update_trigger_(new TaskTrigger(
135 : boost::bind(&PathResolver::ProcessResolverNexthopUpdateList, this),
136 343213 : TaskScheduler::GetInstance()->GetTaskId("bgp::ResolverNexthop"),
137 171629 : 0)),
138 171594 : deleter_(new DeleteActor(this)),
139 686463 : table_delete_ref_(this, table->deleter()) {
140 855036 : for (int part_id = 0; part_id < DB::PartitionCount(); ++part_id) {
141 683446 : partitions_.push_back(new PathResolverPartition(part_id, this));
142 : }
143 171543 : }
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 171632 : PathResolver::~PathResolver() {
155 171632 : assert(listener_id_ != DBTableBase::kInvalidId);
156 171632 : table_->Unregister(listener_id_);
157 171632 : STLDeleteValues(&partitions_);
158 171632 : nexthop_reg_unreg_trigger_->Reset();
159 171632 : nexthop_update_trigger_->Reset();
160 171632 : }
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 3076 : void PathResolver::StartPathResolution(BgpRoute *route, const BgpPath *path,
176 : BgpTable *nh_table) {
177 3076 : CHECK_CONCURRENCY("db::DBTable", "bgp::RouteAggregation",
178 : "bgp::Config", "bgp::ConfigHelper");
179 :
180 3076 : if (!nh_table)
181 166 : nh_table = table_;
182 3076 : assert(nh_table->family() == Address::INET ||
183 : nh_table->family() == Address::INET6);
184 3076 : int part_id = route->get_table_partition()->index();
185 3076 : partitions_[part_id]->StartPathResolution(route, path, nh_table);
186 3076 : }
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 3076 : void PathResolver::StopPathResolution(int part_id, const BgpPath *path) {
195 3076 : CHECK_CONCURRENCY("db::DBTable", "bgp::RouteAggregation",
196 : "bgp::Config", "bgp::ConfigHelper");
197 :
198 3075 : partitions_[part_id]->StopPathResolution(path);
199 3076 : }
200 :
201 : //
202 : // Return the BgpConditionListener for the given family.
203 : //
204 9582 : BgpConditionListener *PathResolver::get_condition_listener(
205 : Address::Family family) {
206 9582 : 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 4986 : void PathResolver::UpdateResolverNexthop(ResolverNexthop *rnexthop) {
229 4986 : std::scoped_lock lock(mutex_);
230 4986 : nexthop_update_list_.insert(rnexthop);
231 4986 : nexthop_update_trigger_->Set();
232 4986 : }
233 :
234 : //
235 : // Get the PathResolverPartition for the given part_id.
236 : //
237 5878 : PathResolverPartition *PathResolver::GetPartition(int part_id) {
238 5878 : 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 7928 : ResolverRouteState *PathResolver::FindResolverRouteState(BgpRoute *route) {
249 : ResolverRouteState *state = static_cast<ResolverRouteState *>(
250 7928 : route->GetState(table_, listener_id_));
251 7932 : 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 3066 : ResolverRouteState *PathResolver::LocateResolverRouteState(BgpRoute *route) {
261 : ResolverRouteState *state = static_cast<ResolverRouteState *>(
262 3066 : route->GetState(table_, listener_id_));
263 3066 : if (state) {
264 1708 : return state;
265 : } else {
266 1358 : 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 3066 : ResolverNexthop *PathResolver::LocateResolverNexthop(IpAddress address,
277 : BgpTable *table) {
278 3066 : CHECK_CONCURRENCY("db::DBTable", "bgp::RouteAggregation",
279 : "bgp::Config", "bgp::ConfigHelper");
280 :
281 3066 : std::scoped_lock lock(mutex_);
282 3066 : ResolverNexthopKey key(address, table);
283 3066 : ResolverNexthopMap::iterator loc = nexthop_map_.find(key);
284 3066 : if (loc != nexthop_map_.end()) {
285 1877 : return loc->second;
286 : } else {
287 1189 : ResolverNexthop *rnexthop = new ResolverNexthop(this, address, table);
288 1189 : nexthop_map_.insert(make_pair(key, rnexthop));
289 1189 : return rnexthop;
290 : }
291 3066 : }
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 1189 : void PathResolver::RemoveResolverNexthop(ResolverNexthop *rnexthop) {
307 1189 : CHECK_CONCURRENCY("bgp::Config");
308 :
309 1189 : ResolverNexthopKey key(rnexthop->address(), rnexthop->table());
310 1189 : ResolverNexthopMap::iterator loc = nexthop_map_.find(key);
311 1189 : assert(loc != nexthop_map_.end());
312 1189 : nexthop_map_.erase(loc);
313 1189 : nexthop_update_list_.erase(rnexthop);
314 1189 : }
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 1173 : void PathResolver::UnregisterResolverNexthopDone(BgpTable *table,
325 : ConditionMatch *match) {
326 1173 : CHECK_CONCURRENCY("db::Walker");
327 :
328 1173 : ResolverNexthop *rnexthop = dynamic_cast<ResolverNexthop *>(match);
329 1173 : assert(rnexthop);
330 1173 : assert(rnexthop->registered());
331 1173 : assert(rnexthop->deleted());
332 1173 : assert(nexthop_delete_list_.find(rnexthop) != nexthop_delete_list_.end());
333 1173 : RegisterUnregisterResolverNexthop(rnexthop);
334 1173 : }
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 4157 : bool PathResolver::ProcessResolverNexthopRegUnreg(ResolverNexthop *rnexthop) {
342 4157 : CHECK_CONCURRENCY("bgp::Config");
343 :
344 4157 : BgpTable *table = rnexthop->table();
345 4157 : Address::Family family = table->family();
346 4157 : BgpConditionListener *condition_listener = get_condition_listener(family);
347 :
348 4157 : 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 1173 : nexthop_delete_list_.erase(rnexthop);
355 1173 : condition_listener->UnregisterMatchCondition(table, rnexthop);
356 1787 : } 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 1173 : RemoveResolverNexthop(rnexthop);
364 1173 : nexthop_delete_list_.insert(rnexthop);
365 : BgpConditionListener::RequestDoneCb cb = boost::bind(
366 1173 : &PathResolver::UnregisterResolverNexthopDone, this, _1, _2);
367 1173 : condition_listener->RemoveMatchCondition(table, rnexthop, cb);
368 1173 : }
369 : } else {
370 1197 : 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 1181 : if (!table->IsDeleted()) {
376 1173 : condition_listener->AddMatchCondition(
377 2346 : table, rnexthop, BgpConditionListener::RequestDoneCb());
378 1173 : 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 4141 : return false;
396 : }
397 :
398 : //
399 : // Handle processing of all ResolverNexthops on the register/unregister list.
400 : //
401 3718 : bool PathResolver::ProcessResolverNexthopRegUnregList() {
402 3718 : CHECK_CONCURRENCY("bgp::Config");
403 :
404 3718 : for (ResolverNexthopList::iterator it = nexthop_reg_unreg_list_.begin();
405 7875 : it != nexthop_reg_unreg_list_.end(); ++it) {
406 4157 : ResolverNexthop *rnexthop = *it;
407 4157 : if (ProcessResolverNexthopRegUnreg(rnexthop))
408 16 : delete rnexthop;
409 : }
410 3718 : nexthop_reg_unreg_list_.clear();
411 :
412 3718 : RetryDelete();
413 3718 : return true;
414 : }
415 :
416 : //
417 : // Handle processing of all ResolverNexthops on the update list.
418 : //
419 3475 : bool PathResolver::ProcessResolverNexthopUpdateList() {
420 3475 : CHECK_CONCURRENCY("bgp::ResolverNexthop");
421 :
422 3475 : for (ResolverNexthopList::iterator it = nexthop_update_list_.begin();
423 8437 : it != nexthop_update_list_.end(); ++it) {
424 4962 : ResolverNexthop *rnexthop = *it;
425 4962 : assert(!rnexthop->deleted());
426 4962 : rnexthop->TriggerAllResolverPaths();
427 : }
428 3475 : nexthop_update_list_.clear();
429 3475 : 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 171632 : void PathResolver::ManagedDelete() {
443 171632 : deleter_->Delete();
444 171632 : }
445 :
446 : //
447 : // Return true if it's safe to delete the PathResolver.
448 : //
449 171736 : bool PathResolver::MayDelete() const {
450 171736 : if (!nexthop_map_.empty())
451 33 : return false;
452 171703 : if (!nexthop_delete_list_.empty())
453 71 : return false;
454 171632 : if (!nexthop_reg_unreg_list_.empty())
455 0 : return false;
456 171632 : assert(nexthop_update_list_.empty());
457 171632 : return true;
458 : }
459 :
460 : //
461 : // Attempt to enqueue a delete for the PathResolver.
462 : //
463 3718 : void PathResolver::RetryDelete() {
464 3718 : if (!deleter_->IsDeleted())
465 3602 : return;
466 116 : deleter_->RetryDelete();
467 : }
468 :
469 : //
470 : // Dummy callback - required in order to get a listener_id for use with
471 : // BgpConditionListener.
472 : //
473 1239232 : bool PathResolver::RouteListener(DBTablePartBase *root, DBEntryBase *entry) {
474 1239232 : 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 683542 : PathResolverPartition::PathResolverPartition(int part_id,
659 683542 : PathResolver *resolver)
660 683542 : : part_id_(part_id),
661 683542 : resolver_(resolver),
662 1367096 : rpath_update_trigger_(new TaskTrigger(
663 : boost::bind(&PathResolverPartition::ProcessResolverPathUpdateList,
664 : this),
665 1367025 : TaskScheduler::GetInstance()->GetTaskId("bgp::ResolverPath"),
666 1367280 : part_id)) {
667 683612 : }
668 :
669 : //
670 : // Destructor for PathResolverPartition.
671 : // All PathResolverPartitions for a PathResolver are destroyed when the
672 : // PathResolver is destroyed.
673 : //
674 683780 : PathResolverPartition::~PathResolverPartition() {
675 683780 : assert(rpath_update_list_.empty());
676 683780 : rpath_update_trigger_->Reset();
677 683780 : }
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 3076 : void PathResolverPartition::StartPathResolution(BgpRoute *route,
688 : const BgpPath *path, BgpTable *nh_table) {
689 3076 : if (!path->IsResolutionFeasible())
690 10 : return;
691 3070 : if (table()->IsDeleted() || nh_table->IsDeleted())
692 0 : return;
693 :
694 3070 : Address::Family family = table()->family();
695 3070 : IpAddress address = path->GetAttr()->nexthop();
696 3070 : if (table() == nh_table && RoutePrefixIsAddress(family, route, address))
697 4 : return;
698 :
699 : ResolverNexthop *rnexthop;
700 3066 : if (family != Address::EVPN) {
701 2349 : rnexthop = resolver_->LocateResolverNexthop(address, nh_table);
702 : }
703 : else {
704 717 : rnexthop = resolver_->LocateResolverNexthop(address, table());
705 : }
706 3066 : assert(!FindResolverPath(path));
707 3066 : ResolverPath *rpath = CreateResolverPath(path, route, rnexthop);
708 3066 : 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 3075 : void PathResolverPartition::StopPathResolution(const BgpPath *path) {
717 3075 : ResolverPath *rpath = RemoveResolverPath(path);
718 3075 : if (!rpath)
719 10 : return;
720 3065 : TriggerPathResolution(rpath);
721 : }
722 :
723 : //
724 : // Add a ResolverPath to the update list and start Task to process the list.
725 : //
726 12009 : void PathResolverPartition::TriggerPathResolution(ResolverPath *rpath) {
727 12009 : CHECK_CONCURRENCY("db::DBTable", "bgp::ResolverNexthop",
728 : "bgp::Config", "bgp::ConfigHelper", "bgp::RouteAggregation");
729 :
730 12010 : rpath_update_list_.insert(rpath);
731 12010 : rpath_update_trigger_->Set();
732 12010 : }
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 6806 : DBTablePartBase *PathResolverPartition::table_partition() {
750 6806 : 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 3066 : ResolverPath *PathResolverPartition::CreateResolverPath(const BgpPath *path,
758 : BgpRoute *route, ResolverNexthop *rnexthop) {
759 3066 : ResolverPath *rpath = new ResolverPath(this, path, route, rnexthop);
760 3066 : rpath_map_.insert(make_pair(path, rpath));
761 3066 : return rpath;
762 : }
763 :
764 : //
765 : // Find the ResolverPath for given BgpPath.
766 : //
767 3064 : ResolverPath *PathResolverPartition::FindResolverPath(const BgpPath *path) {
768 3064 : PathToResolverPathMap::iterator loc = rpath_map_.find(path);
769 3066 : 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 3075 : ResolverPath *PathResolverPartition::RemoveResolverPath(const BgpPath *path) {
779 3075 : PathToResolverPathMap::iterator loc = rpath_map_.find(path);
780 3075 : if (loc == rpath_map_.end()) {
781 10 : return NULL;
782 : } else {
783 3065 : ResolverPath *rpath = loc->second;
784 3065 : rpath_map_.erase(loc);
785 3065 : rpath->clear_path();
786 3065 : return rpath;
787 : }
788 : }
789 :
790 : //
791 : // Handle processing of all ResolverPaths on the update list.
792 : //
793 8770 : bool PathResolverPartition::ProcessResolverPathUpdateList() {
794 8770 : CHECK_CONCURRENCY("bgp::ResolverPath");
795 :
796 8769 : ResolverPathList update_list;
797 8768 : rpath_update_list_.swap(update_list);
798 8763 : for (ResolverPathList::iterator it = update_list.begin();
799 20580 : it != update_list.end(); ++it) {
800 11801 : ResolverPath *rpath = *it;
801 11801 : if (rpath->UpdateResolvedPaths())
802 3066 : delete rpath;
803 : }
804 :
805 17552 : return rpath_update_list_.empty();
806 8776 : }
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 1358 : ResolverRouteState::ResolverRouteState(PathResolver *resolver,
855 1358 : BgpRoute *route)
856 1358 : : resolver_(resolver),
857 1358 : route_(route),
858 1358 : refcount_(0) {
859 1358 : route_->SetState(resolver_->table(), resolver_->listener_id(), this);
860 1358 : }
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 2716 : ResolverRouteState::~ResolverRouteState() {
870 1358 : route_->ClearState(resolver_->table(), resolver_->listener_id());
871 2716 : }
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 3066 : ResolverPath::ResolverPath(PathResolverPartition *partition,
881 3066 : const BgpPath *path, BgpRoute *route, ResolverNexthop *rnexthop)
882 3066 : : partition_(partition),
883 3066 : path_(path),
884 3066 : route_(route),
885 3066 : rnexthop_(rnexthop),
886 3066 : state_(partition_->resolver()->LocateResolverRouteState(route)) {
887 3066 : rnexthop->AddResolverPath(partition->part_id(), this);
888 3066 : }
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 3066 : ResolverPath::~ResolverPath() {
900 3066 : rnexthop_->RemoveResolverPath(partition_->part_id(), this);
901 3066 : }
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 2994 : void ResolverPath::AddResolvedPath(ResolvedPathList::const_iterator it) {
908 2994 : BgpPath *path = *it;
909 2994 : const IPeer *peer = path->GetPeer();
910 2994 : 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 2994 : void ResolverPath::DeleteResolvedPath(ResolvedPathList::const_iterator it) {
926 2994 : BgpPath *path = *it;
927 2994 : const IPeer *peer = path->GetPeer();
928 2994 : 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 6289 : BgpPath *ResolverPath::LocateResolvedPath(const IPeer *peer, uint32_t path_id,
943 : const BgpAttr *attr, uint32_t label, bool is_replicated) {
944 6289 : for (ResolvedPathList::iterator it = resolved_path_list_.begin();
945 6481 : it != resolved_path_list_.end(); ++it) {
946 3485 : BgpPath *path = *it;
947 6970 : if (path->GetPeer() == peer &&
948 6870 : path->GetPathId() == path_id &&
949 10355 : path->GetAttr() == attr &&
950 3353 : path->GetLabel() == label) {
951 3293 : 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 6183 : static ExtCommunityPtr UpdateExtendedCommunity(ExtCommunityDB *extcomm_db,
973 : const BgpAttr *attr, const BgpAttr *nh_attr) {
974 6183 : ExtCommunityPtr ext_community = attr->ext_community();
975 6183 : const ExtCommunity *nh_ext_community = nh_attr->ext_community();
976 6183 : if (!nh_ext_community)
977 904 : return ext_community;
978 :
979 5279 : ExtCommunity::ExtCommunityList rtarget;
980 5279 : ExtCommunity::ExtCommunityList sgid_list;
981 5279 : ExtCommunity::ExtCommunityList encap_list;
982 5279 : ExtCommunity::ExtCommunityValue const *source_as = NULL;
983 5279 : ExtCommunity::ExtCommunityValue const *lb = NULL;
984 5279 : ExtCommunity::ExtCommunityValue const *rt_mac = nullptr;
985 32459 : BOOST_FOREACH(const ExtCommunity::ExtCommunityValue &value,
986 : nh_ext_community->communities()) {
987 21893 : if (ExtCommunity::is_security_group(value) ||
988 8303 : ExtCommunity::is_security_group4(value)) {
989 5287 : sgid_list.push_back(value);
990 8303 : } else if (ExtCommunity::is_tunnel_encap(value)) {
991 6561 : encap_list.push_back(value);
992 1742 : } 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 1632 : } else if (ExtCommunity::is_source_as(value)) {
997 110 : source_as = &value;
998 1522 : } else if (ExtCommunity::is_load_balance(value) && !lb) {
999 8 : lb = &value;
1000 1514 : } 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 10558 : ext_community = extcomm_db->ReplaceRTargetAndLocate(ext_community.get(),
1007 5279 : rtarget);
1008 10558 : ext_community = extcomm_db->ReplaceSGIDListAndLocate(
1009 5279 : ext_community.get(), sgid_list);
1010 10558 : ext_community = extcomm_db->ReplaceTunnelEncapsulationAndLocate(
1011 5279 : ext_community.get(), encap_list);
1012 5279 : if (source_as) {
1013 220 : ext_community = extcomm_db->ReplaceSourceASAndLocate(
1014 110 : ext_community.get(), *source_as);
1015 : }
1016 5279 : if (lb) {
1017 16 : ext_community = extcomm_db->ReplaceLoadBalanceAndLocate(
1018 8 : ext_community.get(), *lb);
1019 : }
1020 5279 : if (rt_mac) {
1021 0 : ext_community = extcomm_db->AppendAndLocate(
1022 0 : ext_community.get(), *rt_mac);
1023 : }
1024 5279 : return ext_community;
1025 5279 : }
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 11802 : bool ResolverPath::UpdateResolvedPaths() {
1038 11802 : 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 11812 : tbb::spin_rw_mutex::scoped_lock rt_write_lock;
1043 11812 : 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 11816 : tbb::spin_rw_mutex::scoped_lock nh_read_lock;
1052 11815 : ResolverRouteState *nh_state = rnexthop_->GetResolverRouteState();
1053 23633 : if (state_ != nh_state &&
1054 23632 : nh_state && !nh_read_lock.try_acquire(nh_state->rw_mutex(), false)) {
1055 0 : partition_->DeferPathResolution(this);
1056 0 : return false;
1057 : }
1058 :
1059 11816 : BgpServer *server = partition_->table()->server();
1060 11816 : BgpAttrDB *attr_db = server->attr_db();
1061 11814 : 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 11812 : ResolvedPathList future_resolved_path_list;
1069 11812 : const BgpRoute *nh_route = rnexthop_->GetRoute();
1070 11813 : const IPeer *peer = path_ ? path_->GetPeer() : NULL;
1071 : // Process paths of nexthop route if nexthop RI is not the master RI.
1072 11813 : const RoutingInstance *nh_ri = rnexthop_->table()->routing_instance();
1073 11813 : bool nh_ri_def = false;
1074 11813 : if (nh_ri->IsMasterRoutingInstance()) {
1075 320 : nh_ri_def = true;
1076 : }
1077 11813 : bool process_paths = false;
1078 11813 : if (path_ && nh_route && !nh_ri_def) {
1079 6118 : process_paths = true;
1080 : }
1081 : Route::PathList::const_iterator it;
1082 11813 : if (process_paths)
1083 12237 : it = nh_route->GetPathList().begin();
1084 30313 : for (; process_paths && it != nh_route->GetPathList().end(); ++it) {
1085 6218 : const BgpPath *nh_path = static_cast<const BgpPath *>(it.operator->());
1086 :
1087 : // Start with attributes of the original path.
1088 6218 : BgpAttrPtr attr(path_->GetAttr());
1089 :
1090 : // Infeasible nexthop paths are not considered.
1091 6222 : if (!nh_path->IsFeasible())
1092 32 : break;
1093 :
1094 : // Take snapshot of all ECMP nexthop paths.
1095 6186 : 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 6156 : if (nh_route->DuplicateForwardingPath(nh_path))
1103 8 : continue;
1104 :
1105 : // Skip if there's no source rd.
1106 6152 : RouteDistinguisher source_rd = nh_path->GetSourceRouteDistinguisher();
1107 6152 : if (source_rd.IsZero())
1108 0 : continue;
1109 :
1110 : // Use source rd from the nexthop path.
1111 6168 : attr = attr_db->ReplaceSourceRdAndLocate(attr.get(), source_rd);
1112 :
1113 : // Use nexthop address from the nexthop path.
1114 12366 : attr = attr_db->ReplaceNexthopAndLocate(attr.get(),
1115 6183 : nh_path->GetAttr()->nexthop());
1116 :
1117 : // obtain extcommunities from original attrs and allow
1118 : // route target type values.
1119 6183 : ExtCommunityPtr ext_community = attr->ext_community();
1120 6183 : ExtCommunity::ExtCommunityList export_list;
1121 6183 : if (ext_community)
1122 : {
1123 548 : BOOST_FOREACH(const ExtCommunity::ExtCommunityValue &v,
1124 : ext_community->communities()) {
1125 184 : if (!ExtCommunity::is_route_target(v))
1126 176 : 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 6183 : UpdateExtendedCommunity(extcomm_db, attr.get(), nh_path->GetAttr());
1134 6183 : if (!export_list.empty()) {
1135 4 : ext_community = extcomm_db->AppendAndLocate(ext_community.get(), export_list);
1136 : }
1137 6183 : attr = attr_db->ReplaceExtCommunityAndLocate(attr.get(), ext_community);
1138 :
1139 : // Locate the resolved path.
1140 6183 : uint32_t path_id = nh_path->GetAttr()->nexthop().to_v4().to_ulong();
1141 : BgpPath *resolved_path =
1142 6183 : LocateResolvedPath(peer, path_id, attr.get(), nh_path->GetLabel());
1143 6183 : future_resolved_path_list.insert(resolved_path);
1144 6223 : }
1145 :
1146 : // If nexthop RI is the default routing-instance, nothing to update except
1147 : // changing path_flags. Locate the resolved path.
1148 11817 : 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 105 : 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 11817 : 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 11819 : if (route_->HasPaths()) {
1169 10439 : if (modified) {
1170 5426 : partition_->table_partition()->Notify(route_);
1171 : }
1172 : } else {
1173 1380 : partition_->table_partition()->Delete(route_);
1174 : }
1175 :
1176 11819 : return (!path_);
1177 11819 : }
1178 :
1179 : //
1180 : // Constructor for ResolverNexthop.
1181 : // Initialize the vector of paths_lists to the number of DB partitions.
1182 : //
1183 1192 : ResolverNexthop::ResolverNexthop(PathResolver *resolver, IpAddress address,
1184 1192 : BgpTable *table)
1185 1195 : : resolver_(resolver),
1186 1195 : address_(address),
1187 1195 : table_(table),
1188 1195 : registered_(false),
1189 1195 : rpath_lists_(DB::PartitionCount()),
1190 3582 : table_delete_ref_(this, table->deleter()) {
1191 1195 : }
1192 :
1193 : //
1194 : // Destructor for ResolverNexthop.
1195 : // A deep delete of the path_lists vector is not required.
1196 : //
1197 2384 : ResolverNexthop::~ResolverNexthop() {
1198 1195 : assert(routes_.empty());
1199 2384 : }
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 51453 : bool ResolverNexthop::Match(BgpServer *server, BgpTable *table,
1212 : BgpRoute *route, bool deleted) {
1213 51453 : CHECK_CONCURRENCY("db::DBTable");
1214 :
1215 : // Ignore if the route doesn't match the address.
1216 51516 : Address::Family family = table->family();
1217 51511 : 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 51511 : if (!resolver_->nexthop_longest_match()) {
1222 51254 : if (!RoutePrefixIsAddress(family, route, address_))
1223 46076 : return false;
1224 : } else {
1225 256 : if (!resolver_->RoutePrefixMatch(route, address_))
1226 28 : return false;
1227 : }
1228 :
1229 : // Do not resolve over self.
1230 10061 : if (route->table() == table && route->IsUsable() &&
1231 4676 : route->BestPath()->GetAttr()->nexthop() == address_) {
1232 4 : return false;
1233 : }
1234 :
1235 : // Set or remove MatchState as appropriate.
1236 : BgpConditionListener *condition_listener =
1237 5425 : resolver_->get_condition_listener(family);
1238 5425 : 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 5429 : bool longest_match_updated = true;
1244 5429 : 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 4270 : 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 5393 : if (ConditionMatch::deleted())
1260 407 : return false;
1261 :
1262 : // Trigger re-evaluation of all dependent ResolverPaths if the longest
1263 : // matching route was updated.
1264 4986 : if (longest_match_updated)
1265 4986 : resolver_->UpdateResolverNexthop(this);
1266 4986 : 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 3066 : void ResolverNexthop::AddResolverPath(int part_id, ResolverPath *rpath) {
1281 3066 : CHECK_CONCURRENCY("db::DBTable", "bgp::RouteAggregation",
1282 : "bgp::Config", "bgp::ConfigHelper");
1283 :
1284 3066 : if (rpath_lists_[part_id].empty())
1285 1505 : resolver_->RegisterUnregisterResolverNexthop(this);
1286 3066 : rpath_lists_[part_id].insert(rpath);
1287 3066 : }
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 3066 : void ResolverNexthop::RemoveResolverPath(int part_id, ResolverPath *rpath) {
1301 3066 : CHECK_CONCURRENCY("bgp::ResolverPath");
1302 :
1303 3066 : rpath_lists_[part_id].erase(rpath);
1304 3066 : if (rpath_lists_[part_id].empty())
1305 1505 : resolver_->RegisterUnregisterResolverNexthop(this);
1306 3066 : }
1307 :
1308 11815 : ResolverRouteState *ResolverNexthop::GetResolverRouteState() {
1309 11815 : if (!GetRoute())
1310 3747 : return NULL;
1311 8068 : PathResolver *nh_resolver = table_->path_resolver();
1312 8069 : if (!nh_resolver)
1313 138 : return NULL;
1314 7931 : 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 4962 : void ResolverNexthop::TriggerAllResolverPaths() const {
1323 4962 : CHECK_CONCURRENCY("bgp::ResolverNexthop");
1324 :
1325 24798 : for (int part_id = 0; part_id < DB::PartitionCount(); ++part_id) {
1326 19836 : for (ResolverPathList::iterator it = rpath_lists_[part_id].begin();
1327 25714 : it != rpath_lists_[part_id].end(); ++it) {
1328 5878 : ResolverPath *rpath = *it;
1329 5878 : resolver_->GetPartition(part_id)->TriggerPathResolution(rpath);
1330 : }
1331 : }
1332 4962 : }
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 9465 : for (int part_id = 0; part_id < DB::PartitionCount(); ++part_id) {
1341 8276 : if (!rpath_lists_[part_id].empty())
1342 1795 : return false;
1343 : }
1344 1189 : return true;
1345 : }
1346 :
1347 2439 : bool ResolverNexthop::ResolverRouteCompare::operator()(
1348 : const BgpRoute *lhs, const BgpRoute *rhs) const {
1349 2439 : const InetRoute *lhs4 = dynamic_cast<const InetRoute *>(lhs);
1350 2439 : const InetRoute *rhs4 = dynamic_cast<const InetRoute *>(rhs);
1351 2439 : if (lhs4) {
1352 1772 : return lhs4->GetPrefix().prefixlen() > rhs4->GetPrefix().prefixlen();
1353 : }
1354 :
1355 667 : const Inet6Route *lhs6 = dynamic_cast<const Inet6Route *>(lhs);
1356 667 : const Inet6Route *rhs6 = dynamic_cast<const Inet6Route *>(rhs);
1357 667 : if (lhs6) {
1358 348 : return lhs6->GetPrefix().prefixlen() > rhs6->GetPrefix().prefixlen();
1359 : }
1360 :
1361 319 : const EvpnRoute *lhs_e = dynamic_cast<const EvpnRoute *>(lhs);
1362 319 : const EvpnRoute *rhs_e = dynamic_cast<const EvpnRoute *>(rhs);
1363 319 : 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 31553 : BgpRoute *ResolverNexthop::GetRoute() {
1396 31553 : std::scoped_lock lock(routes_mutex_);
1397 63102 : return !routes_.empty() ? *(routes_.begin()) : NULL;
1398 31524 : }
|