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