Line data Source code
1 : /*
2 : * Copyright (c) 2015 Juniper Networks, Inc. All rights reserved.
3 : */
4 :
5 : #include "bgp/routing-instance/route_aggregator.h"
6 :
7 : #include <boost/foreach.hpp>
8 :
9 : #include <algorithm>
10 : #include <string>
11 : #include <vector>
12 :
13 : #include "sandesh/sandesh_types.h"
14 : #include "sandesh/sandesh.h"
15 : #include "sandesh/sandesh_trace.h"
16 : #include "base/lifetime.h"
17 : #include "base/map_util.h"
18 : #include "base/task_annotations.h"
19 : #include "base/task_trigger.h"
20 : #include "bgp/bgp_log.h"
21 : #include "bgp/bgp_server.h"
22 : #include "bgp/origin-vn/origin_vn.h"
23 : #include "bgp/routing-instance/path_resolver.h"
24 : #include "bgp/routing-instance/routing_instance.h"
25 : #include "bgp/routing-instance/route_aggregate_types.h"
26 :
27 : using std::make_pair;
28 : using std::string;
29 :
30 : class RouteAggregatorState : public DBState {
31 : public:
32 519 : RouteAggregatorState() : contributor_(false), aggregator_(false) {
33 519 : }
34 :
35 133 : void set_aggregating_info(AggregateRoutePtr aggregator) {
36 133 : assert(!aggregating_info_);
37 133 : aggregating_info_ = aggregator;
38 133 : aggregator_ = true;
39 133 : }
40 :
41 133 : void reset_aggregating_info() {
42 133 : assert(aggregating_info_);
43 133 : aggregating_info_ = NULL;
44 133 : aggregator_ = false;
45 133 : }
46 :
47 397 : void set_contributing_info(AggregateRoutePtr aggregator) {
48 397 : assert(!contributing_info_);
49 397 : contributing_info_ = aggregator;
50 397 : contributor_ = true;
51 397 : }
52 :
53 397 : void reset_contributing_info() {
54 397 : assert(contributing_info_);
55 397 : contributing_info_ = NULL;
56 397 : contributor_ = false;
57 397 : }
58 :
59 : AggregateRoutePtr contributing_info() {
60 : return contributing_info_;
61 : }
62 :
63 : AggregateRoutePtr aggregating_info() {
64 : return aggregating_info_;
65 : }
66 :
67 1287 : bool contributor() const {
68 1287 : return contributor_;
69 : }
70 :
71 631 : bool aggregator() const {
72 631 : return aggregator_;
73 : }
74 :
75 : private:
76 : AggregateRoutePtr contributing_info_;
77 : bool contributor_;
78 : AggregateRoutePtr aggregating_info_;
79 : bool aggregator_;
80 : DISALLOW_COPY_AND_ASSIGN(RouteAggregatorState);
81 : };
82 :
83 : template <typename T>
84 : class AggregateRoute : public ConditionMatch {
85 : public:
86 : typedef typename T::TableT TableT;
87 : typedef typename T::RouteT RouteT;
88 : typedef typename T::PrefixT PrefixT;
89 : typedef typename T::AddressT AddressT;
90 : typedef RouteAggregator<T> AggregateRouteMgrT;
91 : // List of more specific routes resulted in Aggregate route PER PARTITION
92 : typedef std::set<BgpRoute *> RouteList;
93 : typedef std::vector<RouteList> ContributingRouteList;
94 :
95 : enum CompareResult {
96 : NoChange = 0,
97 : NexthopChange = 1,
98 : };
99 :
100 : AggregateRoute(RoutingInstance *rtinstance, AggregateRouteMgrT *manager,
101 : const PrefixT &aggregate_route, IpAddress nexthop);
102 :
103 454 : virtual ~AggregateRoute() {
104 227 : assert(!HasContributingRoutes());
105 681 : }
106 :
107 7770 : Address::Family GetFamily() const { return manager_->GetFamily(); }
108 3349 : AddressT GetAddress(IpAddress addr) const {
109 3349 : return manager_->GetAddress(addr);
110 : }
111 :
112 : // Compare config and return whether cfg has updated
113 : CompareResult CompareConfig(const AggregateRouteConfig &cfg);
114 :
115 490 : const PrefixT &aggregate_route_prefix() const {
116 490 : return aggregate_route_prefix_;
117 : }
118 :
119 4052 : RoutingInstance *routing_instance() const {
120 4052 : return routing_instance_;
121 : }
122 :
123 4316 : BgpTable *bgp_table() const {
124 4316 : return routing_instance_->GetTable(this->GetFamily());
125 : }
126 :
127 277 : BgpRoute *aggregate_route() const {
128 277 : return aggregate_route_;
129 : }
130 :
131 3272 : IpAddress nexthop() const {
132 3272 : return nexthop_;
133 : }
134 :
135 3106 : bool IsMoreSpecific(BgpRoute *route) const {
136 3106 : const RouteT *ip_route = static_cast<RouteT *>(route);
137 3106 : const PrefixT &ip_prefix = ip_route->GetPrefix();
138 3106 : if (ip_prefix.addr() != GetAddress(nexthop()) &&
139 5014 : ip_prefix != aggregate_route_prefix_ &&
140 1908 : ip_prefix.IsMoreSpecific(aggregate_route_prefix_)) {
141 1449 : return true;
142 : }
143 1656 : return false;
144 : }
145 :
146 : bool IsOriginVnMatch(BgpRoute *route) const;
147 : bool IsBestMatch(BgpRoute *route) const;
148 :
149 : virtual bool Match(BgpServer *server, BgpTable *table,
150 : BgpRoute *route, bool deleted);
151 :
152 34 : void UpdateNexthop(IpAddress nexthop) {
153 34 : nexthop_ = nexthop;
154 34 : UpdateAggregateRoute();
155 34 : }
156 :
157 : void AddAggregateRoute();
158 : void UpdateAggregateRoute();
159 : void RemoveAggregateRoute();
160 :
161 : void set_aggregate_route(BgpRoute *aggregate);
162 :
163 0 : virtual string ToString() const {
164 0 : return (string("AggregateRoute ") +
165 0 : aggregate_route_prefix().ToString());
166 : }
167 :
168 : ContributingRouteList *contribute_route_list() {
169 : return &contributors_;
170 : }
171 :
172 560 : const ContributingRouteList &contribute_route_list() const {
173 560 : return contributors_;
174 : }
175 :
176 504 : bool HasContributingRoutes() const {
177 3761 : BOOST_FOREACH(RouteList per_part_contributor, contribute_route_list()) {
178 1700 : if (!per_part_contributor.empty()) {
179 143 : return true;
180 : }
181 : }
182 361 : return false;
183 : }
184 :
185 999 : bool IsContributingRoute(BgpRoute *route) const {
186 999 : uint32_t part_id = route->get_table_partition()->index();
187 999 : return (contributors_[part_id].find(route) !=
188 1997 : contributors_[part_id].end());
189 : }
190 :
191 794 : void NotifyContributingRoute(BgpRoute *route) {
192 794 : DBRequest req;
193 794 : req.oper = DBRequest::DB_ENTRY_NOTIFY;
194 794 : RouteT *ip_route = static_cast<RouteT *>(route);
195 794 : const PrefixT &prefix = ip_route->GetPrefix();
196 794 : req.key.reset(new typename TableT::RequestKey(prefix, NULL));
197 794 : bgp_table()->Enqueue(&req);
198 794 : }
199 :
200 530 : RouteAggregatorState *LocateRouteState(BgpRoute *route) {
201 : RouteAggregatorState *state = static_cast<RouteAggregatorState *>
202 530 : (route->GetState(bgp_table(), manager_->listener_id()));
203 530 : if (state == NULL) {
204 519 : state = new RouteAggregatorState();
205 519 : route->SetState(bgp_table(), manager_->listener_id(), state);
206 : }
207 530 : return state;
208 : }
209 :
210 397 : bool AddContributingRoute(BgpRoute *route) {
211 397 : uint32_t part_id = route->get_table_partition()->index();
212 397 : contributors_[part_id].insert(route);
213 397 : RouteAggregatorState *state = LocateRouteState(route);
214 397 : state->set_contributing_info(AggregateRoutePtr(this));
215 397 : NotifyContributingRoute(route);
216 397 : return (contributors_[part_id].size() == 1);
217 : }
218 :
219 530 : void ClearRouteState(BgpRoute *route, RouteAggregatorState *state) {
220 530 : if (!state->aggregator() && !state->contributor()) {
221 519 : route->ClearState(bgp_table(), manager_->listener_id());
222 519 : delete state;
223 : }
224 530 : }
225 :
226 397 : bool RemoveContributingRoute(BgpRoute *route) {
227 397 : uint32_t part_id = route->get_table_partition()->index();
228 397 : int num_deleted = contributors_[part_id].erase(route);
229 : RouteAggregatorState *state = static_cast<RouteAggregatorState *>
230 397 : (route->GetState(bgp_table(), manager_->listener_id()));
231 397 : if (state) {
232 397 : state->reset_contributing_info();
233 397 : ClearRouteState(route, state);
234 397 : NotifyContributingRoute(route);
235 : } else {
236 0 : assert(num_deleted != 1);
237 : }
238 397 : return contributors_[part_id].empty();
239 : }
240 :
241 : void FillShowInfo(AggregateRouteInfo *info, bool summary) const;
242 :
243 : private:
244 : RoutingInstance *routing_instance_;
245 : AggregateRouteMgrT *manager_;
246 : PrefixT aggregate_route_prefix_;
247 : IpAddress nexthop_;
248 : BgpRoute *aggregate_route_;
249 : ContributingRouteList contributors_;
250 :
251 : DISALLOW_COPY_AND_ASSIGN(AggregateRoute);
252 : };
253 :
254 : template <typename T>
255 227 : AggregateRoute<T>::AggregateRoute(RoutingInstance *rtinstance,
256 : AggregateRouteMgrT *manager, const PrefixT &aggregate_route,
257 : IpAddress nexthop)
258 227 : : routing_instance_(rtinstance),
259 227 : manager_(manager),
260 227 : aggregate_route_prefix_(aggregate_route),
261 227 : nexthop_(nexthop),
262 227 : aggregate_route_(NULL),
263 454 : contributors_(ContributingRouteList(DB::PartitionCount())) {
264 227 : }
265 :
266 : // Compare config and return whether cfg has updated
267 : template <typename T>
268 77 : typename AggregateRoute<T>::CompareResult AggregateRoute<T>::CompareConfig(
269 : const AggregateRouteConfig &cfg) {
270 77 : AddressT address = this->GetAddress(cfg.aggregate);
271 77 : PrefixT prefix(address, cfg.prefix_length);
272 77 : assert(aggregate_route_prefix_ == prefix);
273 77 : if (nexthop_ != cfg.nexthop) {
274 34 : return NexthopChange;
275 : }
276 43 : return NoChange;
277 : }
278 :
279 : template <typename T>
280 1888 : bool AggregateRoute<T>::IsOriginVnMatch(BgpRoute *route) const {
281 1888 : const BgpPath *path = route->BestPath();
282 1887 : const BgpAttr *attr = path->GetAttr();
283 1887 : const ExtCommunity *ext_community = attr->ext_community();
284 1887 : int vni = 0;
285 1887 : if (ext_community) {
286 1077 : BOOST_FOREACH(const ExtCommunity::ExtCommunityValue &comm,
287 : ext_community->communities()) {
288 531 : if (!ExtCommunity::is_origin_vn(comm)) continue;
289 477 : OriginVn origin_vn(comm);
290 477 : vni = origin_vn.vn_index();
291 477 : break;
292 : }
293 : }
294 :
295 1887 : if (!vni && path->IsVrfOriginated())
296 1669 : vni = routing_instance()->virtual_network_index();
297 :
298 1887 : if (vni == routing_instance()->GetOriginVnForAggregateRoute(GetFamily()))
299 1868 : return true;
300 :
301 18 : return false;
302 : }
303 :
304 : //
305 : // Calculate all aggregate prefixes to which the route can be contributing.
306 : // We need to calculate the longest prefix to which this route belongs.
307 : // E.g. routing instance is configured with 1/8, 1.1/16 and 1.1.1/24, 1.1.1.1/32
308 : // should match 1.1.1/24. Similarly, 1.1.1/24 should be most specific to 1.1/16
309 : // as so on
310 : //
311 : template <typename T>
312 1517 : bool AggregateRoute<T>::IsBestMatch(BgpRoute *route) const {
313 1517 : const RouteT *ip_route = static_cast<RouteT *>(route);
314 1517 : const PrefixT &ip_prefix = ip_route->GetPrefix();
315 1517 : typename RouteAggregator<T>::AggregateRouteMap::const_iterator it;
316 1517 : std::set<PrefixT> prefix_list;
317 1517 : for (it = manager_->aggregate_route_map().begin();
318 3425 : it != manager_->aggregate_route_map().end(); ++it) {
319 3736 : if (!it->second->deleted() && ip_prefix != it->first &&
320 1828 : ip_prefix.IsMoreSpecific(it->first)) {
321 1612 : prefix_list.insert(it->first);
322 : }
323 : }
324 : // It should match atleast one prefix
325 1517 : assert(prefix_list.size());
326 : //
327 : // Longest prefix matches the aggregate prefix of current AggregateRoute
328 : // return true to make this route as contributing route
329 : // Longest prefix is the last prefix in the set
330 : //
331 1517 : if (*(prefix_list.rbegin()) == aggregate_route_prefix_) return true;
332 10 : return false;
333 1517 : }
334 :
335 : // Match function called from BgpConditionListener
336 : // Concurrency : db::DBTable
337 : template <typename T>
338 3118 : bool AggregateRoute<T>::Match(BgpServer *server, BgpTable *table,
339 : BgpRoute *route, bool deleted) {
340 3118 : CHECK_CONCURRENCY("db::DBTable");
341 :
342 : //
343 : // Only interested routes
344 : // Should satisfy following conditions
345 : // 1. Origin VN should match origin VN of aggregated route
346 : // 2. Route should be more specific
347 : //
348 3121 : if ((!deleted && !IsOriginVnMatch(route)) || !IsMoreSpecific(route))
349 1674 : return false;
350 :
351 1449 : if (!deleted) {
352 : //
353 : // If the route is already contributing, check whether it is still
354 : // most specific aggregate prefix. Else remove the route as contributing
355 : // route. As part of the notification, route will become contributing to
356 : // most specific aggregate route prefix.
357 : //
358 999 : if (IsContributingRoute(route)) {
359 556 : if (!IsBestMatch(route)) deleted = true;
360 442 : } else if (table->IsContributingRoute(route)) {
361 : //
362 : // If the route is already contributing route of other aggregate
363 : // prefix of this bgp-table, ignore it
364 : //
365 37 : return false;
366 : }
367 : }
368 :
369 : //
370 : // Consider route only if it matches most specific aggregate prefix
371 : // configured on the routing instance. e.g. if routing instance has
372 : // following prefixes configured, 1/8, 1.1/16 and 1.1.1/24,
373 : // 1.1.1.1/32 should match to 1.1.1/24 as most specific route.
374 : //
375 1412 : if (!deleted && !IsBestMatch(route)) return false;
376 :
377 1403 : BgpConditionListener *listener = server->condition_listener(GetFamily());
378 1402 : bool state_added = listener->CheckMatchState(table, route, this);
379 1403 : bool trigger_eval = false;
380 1403 : if (!deleted) {
381 952 : if (!state_added) {
382 397 : listener->SetMatchState(table, route, this);
383 397 : trigger_eval = AddContributingRoute(route);
384 : }
385 : } else {
386 451 : if (!state_added) {
387 : // Not seen ADD ignore DELETE
388 54 : return false;
389 : }
390 397 : trigger_eval = RemoveContributingRoute(route);
391 397 : listener->RemoveMatchState(table, route, this);
392 : }
393 :
394 1349 : if (trigger_eval) manager_->EvaluateAggregateRoute(this);
395 1349 : return true;
396 : }
397 :
398 : // AddAggregateRoute
399 : template <typename T>
400 133 : void AggregateRoute<T>::AddAggregateRoute() {
401 133 : CHECK_CONCURRENCY("bgp::RouteAggregation");
402 :
403 133 : RouteT rt_key(aggregate_route_prefix());
404 : DBTablePartition *partition =
405 133 : static_cast<DBTablePartition *>(bgp_table()->GetTablePartition(&rt_key));
406 : BgpRoute *aggregate_route =
407 133 : static_cast<BgpRoute *>(partition->Find(&rt_key));
408 :
409 133 : if (aggregate_route == NULL) {
410 130 : aggregate_route = new RouteT(aggregate_route_prefix());
411 130 : partition->Add(aggregate_route);
412 : } else {
413 3 : aggregate_route->ClearDelete();
414 : }
415 :
416 133 : BgpPath *existing_path = aggregate_route->FindPath(BgpPath::Aggregate, 0);
417 133 : assert(existing_path == NULL);
418 :
419 133 : BgpAttrSpec attrs;
420 133 : BgpAttrNextHop attr_nexthop(this->GetAddress(nexthop()));
421 133 : attrs.push_back(&attr_nexthop);
422 133 : ExtCommunitySpec extcomm_spec;
423 133 : OriginVn origin_vn(routing_instance()->server()->autonomous_system(),
424 133 : routing_instance()->GetOriginVnForAggregateRoute(GetFamily()));
425 133 : extcomm_spec.communities.push_back(origin_vn.GetExtCommunityValue());
426 133 : attrs.push_back(&extcomm_spec);
427 133 : BgpAttrPtr attr = routing_instance()->server()->attr_db()->Locate(attrs);
428 133 : BgpPath *new_path = new BgpPath(BgpPath::Aggregate,
429 : attr.get(), BgpPath::ResolveNexthop, 0);
430 133 : bgp_table()->path_resolver()->StartPathResolution(aggregate_route,
431 : new_path);
432 133 : aggregate_route->InsertPath(new_path);
433 133 : partition->Notify(aggregate_route);
434 133 : set_aggregate_route(aggregate_route);
435 :
436 133 : BGP_LOG_STR(BgpMessage, SandeshLevel::SYS_DEBUG, BGP_LOG_FLAG_TRACE,
437 : "Added aggregate path " << aggregate_route_->ToString() <<
438 : " in table " << partition->table()->name());
439 133 : }
440 :
441 : // UpdateAggregateRoute
442 : template <typename T>
443 34 : void AggregateRoute<T>::UpdateAggregateRoute() {
444 34 : CHECK_CONCURRENCY("bgp::Config", "bgp::ConfigHelper");
445 :
446 34 : if (aggregate_route_ == NULL) return;
447 :
448 : DBTablePartition *partition = static_cast<DBTablePartition *>
449 33 : (bgp_table()->GetTablePartition(aggregate_route_));
450 :
451 33 : aggregate_route_->ClearDelete();
452 :
453 33 : BgpPath *existing_path = aggregate_route_->FindPath(BgpPath::Aggregate, 0);
454 33 : if (existing_path)
455 33 : bgp_table()->path_resolver()->StopPathResolution(partition->index(),
456 : existing_path);
457 33 : aggregate_route_->RemovePath(BgpPath::Aggregate);
458 :
459 33 : BgpAttrSpec attrs;
460 33 : BgpAttrNextHop attr_nexthop(this->GetAddress(nexthop()));
461 33 : attrs.push_back(&attr_nexthop);
462 33 : ExtCommunitySpec extcomm_spec;
463 33 : OriginVn origin_vn(routing_instance()->server()->autonomous_system(),
464 33 : routing_instance()->GetOriginVnForAggregateRoute(GetFamily()));
465 33 : extcomm_spec.communities.push_back(origin_vn.GetExtCommunityValue());
466 33 : attrs.push_back(&extcomm_spec);
467 33 : BgpAttrPtr attr = routing_instance()->server()->attr_db()->Locate(attrs);
468 33 : BgpPath *new_path = new BgpPath(BgpPath::Aggregate,
469 : attr.get(), BgpPath::ResolveNexthop, 0);
470 33 : bgp_table()->path_resolver()->StartPathResolution(aggregate_route_,
471 : new_path);
472 33 : aggregate_route_->InsertPath(new_path);
473 :
474 33 : partition->Notify(aggregate_route_);
475 :
476 33 : BGP_LOG_STR(BgpMessage, SandeshLevel::SYS_DEBUG, BGP_LOG_FLAG_TRACE,
477 : "Updated aggregate path " << aggregate_route_->ToString() <<
478 : " in table " << partition->table()->name());
479 33 : }
480 :
481 : // RemoveAggregateRoute
482 : template <typename T>
483 133 : void AggregateRoute<T>::RemoveAggregateRoute() {
484 133 : CHECK_CONCURRENCY("bgp::RouteAggregation");
485 133 : BgpRoute *aggregate_route = aggregate_route_;
486 133 : if (!aggregate_route) return;
487 :
488 : DBTablePartition *partition = static_cast<DBTablePartition *>
489 133 : (bgp_table()->GetTablePartition(aggregate_route_));
490 :
491 : BgpPath *existing_path =
492 133 : aggregate_route->FindPath(BgpPath::Aggregate, 0);
493 133 : assert(existing_path != NULL);
494 :
495 133 : bgp_table()->path_resolver()->StopPathResolution(partition->index(),
496 : existing_path);
497 133 : aggregate_route->RemovePath(BgpPath::Aggregate);
498 :
499 133 : BGP_LOG_STR(BgpMessage, SandeshLevel::SYS_DEBUG, BGP_LOG_FLAG_TRACE,
500 : "Removed aggregate path " << aggregate_route_->ToString() <<
501 : " in table " << partition->table()->name());
502 :
503 133 : if (!aggregate_route->HasPaths()) {
504 15 : partition->Delete(aggregate_route);
505 : } else {
506 118 : partition->Notify(aggregate_route);
507 : }
508 133 : set_aggregate_route(NULL);
509 : }
510 :
511 : template <typename T>
512 266 : void AggregateRoute<T>::set_aggregate_route(BgpRoute *aggregate) {
513 266 : if (aggregate) {
514 133 : assert(aggregate_route_ == NULL);
515 133 : RouteAggregatorState *state = LocateRouteState(aggregate);
516 133 : state->set_aggregating_info(AggregateRoutePtr(this));
517 : } else {
518 133 : assert(aggregate_route_ != NULL);
519 : RouteAggregatorState *state = static_cast<RouteAggregatorState *>
520 133 : (aggregate_route_->GetState(bgp_table(), manager_->listener_id()));
521 133 : assert(state);
522 133 : state->reset_aggregating_info();
523 133 : ClearRouteState(aggregate_route_, state);
524 : }
525 266 : aggregate_route_ = aggregate;
526 266 : }
527 :
528 : template <typename T>
529 112 : void AggregateRoute<T>::FillShowInfo(AggregateRouteInfo *info,
530 : bool summary) const {
531 112 : BgpTable *table = bgp_table();
532 112 : info->set_deleted(deleted());
533 112 : info->set_prefix(aggregate_route_prefix_.ToString());
534 112 : if (aggregate_route_) {
535 98 : ShowRouteBrief show_route;
536 98 : aggregate_route_->FillRouteInfo(table, &show_route);
537 98 : info->set_aggregate_rt(show_route);
538 98 : }
539 :
540 112 : info->set_nexthop(nexthop_.to_string());
541 :
542 112 : if (summary)
543 56 : return;
544 :
545 56 : std::vector<string> contributor_list;
546 504 : BOOST_FOREACH(const RouteList &list, contribute_route_list()) {
547 848 : BOOST_FOREACH(BgpRoute *rt, list) {
548 312 : contributor_list.push_back(rt->ToString());
549 : }
550 : }
551 56 : info->set_contributors(contributor_list);
552 56 : }
553 :
554 : template <typename T>
555 : class RouteAggregator<T>::DeleteActor : public LifetimeActor {
556 : public:
557 160 : explicit DeleteActor(RouteAggregator *aggregator) :
558 : LifetimeActor(aggregator->routing_instance()->server()->lifetime_manager()),
559 160 : aggregator_(aggregator) {
560 160 : }
561 320 : virtual ~DeleteActor() {
562 320 : }
563 :
564 313 : virtual bool MayDelete() const {
565 313 : return aggregator_->MayDelete();
566 : }
567 :
568 160 : virtual void Destroy() {
569 320 : aggregator_->routing_instance()->DestroyRouteAggregator(
570 160 : aggregator_->GetFamily());
571 160 : }
572 :
573 : private:
574 : RouteAggregator *aggregator_;
575 : };
576 :
577 : template <typename T>
578 160 : RouteAggregator<T>::RouteAggregator(RoutingInstance *rtinstance)
579 160 : : rtinstance_(rtinstance),
580 160 : condition_listener_(rtinstance_->server()->condition_listener(GetFamily())),
581 160 : listener_id_(DBTableBase::kInvalidId),
582 320 : update_list_trigger_(new TaskTrigger(
583 : boost::bind(&RouteAggregator::ProcessUpdateList, this),
584 320 : TaskScheduler::GetInstance()->GetTaskId("bgp::RouteAggregation"),
585 : 0)),
586 320 : unregister_list_trigger_(new TaskTrigger(
587 : boost::bind(&RouteAggregator::ProcessUnregisterList, this),
588 320 : TaskScheduler::GetInstance()->GetTaskId("bgp::Config"), 0)),
589 160 : deleter_(new DeleteActor(this)),
590 640 : instance_delete_ref_(this, rtinstance->deleter()) {
591 160 : }
592 :
593 : template <typename T>
594 320 : RouteAggregator<T>::~RouteAggregator() {
595 160 : if (listener_id_ != DBTableBase::kInvalidId)
596 160 : bgp_table()->Unregister(listener_id_);
597 160 : listener_id_ = DBTableBase::kInvalidId;
598 480 : }
599 :
600 : template <typename T>
601 178 : void RouteAggregator<T>::ProcessAggregateRouteConfig() {
602 178 : CHECK_CONCURRENCY("bgp::Config", "bgp::ConfigHelper");
603 : const AggregateRouteConfigList &list =
604 178 : routing_instance()->config()->aggregate_routes(GetFamily());
605 : typedef AggregateRouteConfigList::const_iterator iterator_t;
606 402 : for (iterator_t iter = list.begin(); iter != list.end(); ++iter) {
607 224 : LocateAggregateRoutePrefix(*iter);
608 : }
609 178 : }
610 :
611 36 : bool CompareAggregateRouteConfig(const AggregateRouteConfig &lhs,
612 : const AggregateRouteConfig &rhs) {
613 36 : BOOL_KEY_COMPARE(lhs.aggregate, rhs.aggregate);
614 2 : BOOL_KEY_COMPARE(lhs.prefix_length, rhs.prefix_length);
615 2 : return false;
616 : }
617 :
618 : template <typename T>
619 74 : void RouteAggregator<T>::UpdateAggregateRouteConfig() {
620 74 : CHECK_CONCURRENCY("bgp::Config", "bgp::ConfigHelper");
621 74 : AggregateRouteConfigList config_list =
622 74 : routing_instance()->config()->aggregate_routes(GetFamily());
623 74 : sort(config_list.begin(), config_list.end(), CompareAggregateRouteConfig);
624 :
625 74 : map_difference(&aggregate_route_map_,
626 : config_list.begin(), config_list.end(),
627 : boost::bind(&RouteAggregator<T>::CompareAggregateRoute, this, _1, _2),
628 : boost::bind(&RouteAggregator<T>::AddAggregateRoute, this, _1),
629 : boost::bind(&RouteAggregator<T>::DelAggregateRoute, this, _1),
630 : boost::bind(&RouteAggregator<T>::UpdateAggregateRoute, this, _1, _2));
631 74 : }
632 :
633 : template <typename T>
634 277 : void RouteAggregator<T>::FlushAggregateRouteConfig() {
635 277 : CHECK_CONCURRENCY("bgp::Config");
636 277 : for (typename AggregateRouteMap::iterator it = aggregate_route_map_.begin();
637 631 : it != aggregate_route_map_.end(); it++) {
638 354 : RemoveAggregateRoutePrefix(it->first);
639 : }
640 277 : }
641 :
642 : template <>
643 10531 : Address::Family RouteAggregator<AggregateInetRoute>::GetFamily() const {
644 10531 : return Address::INET;
645 : }
646 :
647 : template <>
648 228 : Address::Family RouteAggregator<AggregateInet6Route>::GetFamily() const {
649 228 : return Address::INET6;
650 : }
651 :
652 : template <>
653 3647 : Ip4Address RouteAggregator<AggregateInetRoute>::GetAddress(IpAddress addr)
654 : const {
655 3647 : assert(addr.is_v4());
656 3647 : return addr.to_v4();
657 : }
658 :
659 : template <>
660 78 : Ip6Address RouteAggregator<AggregateInet6Route>::GetAddress(IpAddress addr)
661 : const {
662 78 : assert(addr.is_v6());
663 78 : return addr.to_v6();
664 : }
665 :
666 : template <typename T>
667 2417 : BgpTable *RouteAggregator<T>::bgp_table() const {
668 2417 : return rtinstance_->GetTable(GetFamily());
669 : }
670 :
671 : template <typename T>
672 160 : void RouteAggregator<T>::Initialize() {
673 : // Register to the table before adding first match condition
674 160 : listener_id_ = bgp_table()->Register(
675 : boost::bind(&RouteAggregator::RouteListener, this, _1, _2),
676 : "RouteAggregator");
677 160 : }
678 :
679 : template <typename T>
680 742 : bool RouteAggregator<T>::MayDelete() const {
681 742 : if (!aggregate_route_map_.empty())
682 418 : return false;
683 324 : if (!update_aggregate_list_.empty())
684 3 : return false;
685 321 : if (!unregister_aggregate_list_.empty())
686 0 : return false;
687 321 : return true;
688 : }
689 :
690 : // Cascade delete from RoutingInstance delete_ref to self.
691 : template <typename T>
692 160 : void RouteAggregator<T>::ManagedDelete() {
693 160 : deleter_->Delete();
694 160 : }
695 :
696 : // Attempt to enqueue a delete for the RouteAggregator.
697 : template <typename T>
698 161 : void RouteAggregator<T>::RetryDelete() {
699 161 : if (!deleter_->IsDeleted())
700 8 : return;
701 153 : deleter_->RetryDelete();
702 : }
703 :
704 : template <typename T>
705 288 : void RouteAggregator<T>::EvaluateAggregateRoute(AggregateRoutePtr entry) {
706 288 : std::scoped_lock lock(mutex_);
707 288 : update_aggregate_list_.insert(entry);
708 288 : update_list_trigger_->Set();
709 288 : }
710 :
711 : template <typename T>
712 227 : void RouteAggregator<T>::UnregisterAndResolveRouteAggregate(
713 : AggregateRoutePtr entry) {
714 227 : std::scoped_lock lock(mutex_);
715 227 : unregister_aggregate_list_.insert(entry);
716 227 : unregister_list_trigger_->Set();
717 227 : }
718 :
719 : template <typename T>
720 200 : bool RouteAggregator<T>::IsAggregateRoute(const BgpRoute *route) const {
721 : RouteAggregatorState *state = static_cast<RouteAggregatorState *>
722 200 : (route->GetState(bgp_table(), listener_id()));
723 200 : if (state) {
724 101 : return (state->aggregator());
725 : }
726 99 : return false;
727 : }
728 :
729 : template <typename T>
730 1897 : bool RouteAggregator<T>::IsContributingRoute(const BgpRoute *route) const {
731 : RouteAggregatorState *state = static_cast<RouteAggregatorState *>
732 1897 : (route->GetState(bgp_table(), listener_id()));
733 1897 : if (state) {
734 761 : return state->contributor();
735 : }
736 1136 : return false;
737 : }
738 :
739 : template <typename T>
740 82 : bool RouteAggregator<T>::FillAggregateRouteInfo(AggregateRouteEntriesInfo *info,
741 : bool summary) const {
742 82 : if (aggregate_route_map().empty())
743 6 : return false;
744 :
745 76 : info->set_name(rtinstance_->GetVirtualNetworkName());
746 76 : info->set_instance_name(rtinstance_->name());
747 76 : vector<AggregateRouteInfo> aggregate_route_list =
748 : vector<AggregateRouteInfo>();
749 188 : for (typename AggregateRouteMap::const_iterator it =
750 264 : aggregate_route_map_.begin(); it != aggregate_route_map_.end(); it++) {
751 : AggregateRouteT *aggregate =
752 112 : static_cast<AggregateRouteT *>(it->second.get());
753 112 : AggregateRouteInfo aggregate_info;
754 112 : aggregate->FillShowInfo(&aggregate_info, summary);
755 112 : aggregate_route_list.push_back(aggregate_info);
756 : }
757 76 : info->set_aggregate_route_list(aggregate_route_list);
758 76 : return true;
759 76 : }
760 :
761 : template <typename T>
762 73 : int RouteAggregator<T>::CompareAggregateRoute(
763 : typename AggregateRouteMap::iterator loc,
764 : AggregateRouteConfigList::iterator it) {
765 73 : AddressT address = this->GetAddress(it->aggregate);
766 73 : PrefixT prefix(address, it->prefix_length);
767 73 : KEY_COMPARE(loc->first, prefix);
768 58 : return 0;
769 : }
770 :
771 : template <typename T>
772 23 : void RouteAggregator<T>::AddAggregateRoute(
773 : AggregateRouteConfigList::iterator it) {
774 23 : LocateAggregateRoutePrefix(*it);
775 23 : }
776 :
777 : template <typename T>
778 24 : void RouteAggregator<T>::DelAggregateRoute(
779 : typename AggregateRouteMap::iterator loc) {
780 24 : RemoveAggregateRoutePrefix(loc->first);
781 24 : }
782 :
783 : template <typename T>
784 58 : void RouteAggregator<T>::UpdateAggregateRoute(
785 : typename AggregateRouteMap::iterator loc,
786 : AggregateRouteConfigList::iterator it) {
787 58 : LocateAggregateRoutePrefix(*it);
788 58 : }
789 :
790 : template <typename T>
791 305 : void RouteAggregator<T>::LocateAggregateRoutePrefix(const AggregateRouteConfig
792 : &cfg) {
793 305 : CHECK_CONCURRENCY("bgp::Config", "bgp::ConfigHelper");
794 305 : AddressT address = this->GetAddress(cfg.aggregate);
795 305 : PrefixT prefix(address, cfg.prefix_length);
796 :
797 : // Verify whether the entry already exists
798 305 : typename AggregateRouteMap::iterator it = aggregate_route_map_.find(prefix);
799 305 : if (it != aggregate_route_map_.end()) {
800 : // Wait for the delete complete cb
801 78 : if (it->second->deleted()) return;
802 :
803 : AggregateRouteT *match =
804 77 : static_cast<AggregateRouteT *>(it->second.get());
805 : // Check whether the config has got updated
806 : typename AggregateRouteT::CompareResult change =
807 77 : match->CompareConfig(cfg);
808 : // No change..
809 77 : if (change == AggregateRouteT::NoChange) return;
810 :
811 34 : if (change == AggregateRouteT::NexthopChange)
812 34 : match->UpdateNexthop(cfg.nexthop);
813 34 : return;
814 : }
815 :
816 0 : AggregateRouteT *match =
817 227 : new AggregateRouteT(routing_instance(), this, prefix, cfg.nexthop);
818 227 : AggregateRoutePtr aggregate_route_match = AggregateRoutePtr(match);
819 227 : aggregate_route_map_.insert(make_pair(prefix, aggregate_route_match));
820 :
821 227 : condition_listener_->AddMatchCondition(match->bgp_table(),
822 454 : aggregate_route_match.get(), BgpConditionListener::RequestDoneCb());
823 227 : return;
824 227 : }
825 :
826 : template <typename T>
827 378 : void RouteAggregator<T>::RemoveAggregateRoutePrefix(const PrefixT &aggregate) {
828 378 : CHECK_CONCURRENCY("bgp::Config", "bgp::ConfigHelper");
829 : typename AggregateRouteMap::iterator it =
830 378 : aggregate_route_map_.find(aggregate);
831 529 : if (it == aggregate_route_map_.end()) return;
832 378 : if (it->second->deleted()) return;
833 :
834 227 : BgpConditionListener::RequestDoneCb callback =
835 : boost::bind(&RouteAggregator::StopAggregateRouteDone, this, _1, _2);
836 :
837 227 : AggregateRouteT *match = static_cast<AggregateRouteT *>(it->second.get());
838 227 : condition_listener_->RemoveMatchCondition(match->bgp_table(),
839 : match, callback);
840 227 : }
841 :
842 : template <typename T>
843 227 : void RouteAggregator<T>::StopAggregateRouteDone(BgpTable *table,
844 : ConditionMatch *info) {
845 227 : CHECK_CONCURRENCY("db::Walker");
846 227 : UnregisterAndResolveRouteAggregate(info);
847 227 : return;
848 : }
849 :
850 : template <typename T>
851 174 : bool RouteAggregator<T>::ProcessUnregisterList() {
852 174 : CHECK_CONCURRENCY("bgp::Config");
853 :
854 174 : for (AggregateRouteProcessList::iterator
855 174 : it = unregister_aggregate_list_.begin();
856 401 : it != unregister_aggregate_list_.end(); ++it) {
857 227 : AggregateRouteT *aggregate = static_cast<AggregateRouteT *>(it->get());
858 227 : aggregate_route_map_.erase(aggregate->aggregate_route_prefix());
859 227 : condition_listener_->UnregisterMatchCondition(aggregate->bgp_table(),
860 : aggregate);
861 : }
862 :
863 174 : unregister_aggregate_list_.clear();
864 :
865 174 : if (!routing_instance()->deleted() && routing_instance()->config())
866 21 : ProcessAggregateRouteConfig();
867 :
868 174 : if (MayDelete()) RetryDelete();
869 174 : return true;
870 : }
871 :
872 : template <typename T>
873 255 : bool RouteAggregator<T>::ProcessUpdateList() {
874 255 : CHECK_CONCURRENCY("bgp::RouteAggregation");
875 :
876 255 : for (AggregateRouteProcessList::iterator
877 255 : it = update_aggregate_list_.begin();
878 532 : it != update_aggregate_list_.end(); ++it) {
879 277 : AggregateRouteT *aggregate = static_cast<AggregateRouteT *>(it->get());
880 277 : if (aggregate->aggregate_route()) {
881 143 : if (!aggregate->HasContributingRoutes())
882 133 : aggregate->RemoveAggregateRoute();
883 : } else {
884 134 : if (aggregate->HasContributingRoutes())
885 133 : aggregate->AddAggregateRoute();
886 : }
887 : }
888 :
889 255 : update_aggregate_list_.clear();
890 :
891 255 : if (MayDelete()) RetryDelete();
892 255 : return true;
893 : }
894 :
895 : // Need this to store the aggregate info in aggregated route as DBState
896 : template <typename T>
897 2055 : bool RouteAggregator<T>::RouteListener(DBTablePartBase *root,
898 : DBEntryBase *entry) {
899 2055 : return true;
900 : }
901 :
902 : // Enable/Disable task triggers
903 : template <typename T>
904 3 : void RouteAggregator<T>::DisableRouteAggregateUpdate() {
905 3 : update_list_trigger_->set_disable();
906 3 : }
907 :
908 : template <typename T>
909 3 : void RouteAggregator<T>::EnableRouteAggregateUpdate() {
910 3 : update_list_trigger_->set_enable();
911 3 : }
912 :
913 : template <typename T>
914 3 : size_t RouteAggregator<T>::GetUpdateAggregateListSize() const {
915 3 : return update_aggregate_list_.size();
916 : }
917 :
918 : template <typename T>
919 1 : void RouteAggregator<T>::DisableUnregResolveTask() {
920 1 : unregister_list_trigger_->set_disable();
921 1 : }
922 :
923 : template <typename T>
924 1 : void RouteAggregator<T>::EnableUnregResolveTask() {
925 1 : unregister_list_trigger_->set_enable();
926 1 : }
927 :
928 : template <typename T>
929 3 : size_t RouteAggregator<T>::GetUnregResolveListSize() const {
930 3 : return unregister_aggregate_list_.size();
931 : }
932 :
933 : // Explicit instantiation of RouteAggregator for INET and INET6.
934 : template class RouteAggregator<AggregateInetRoute>;
935 : template class RouteAggregator<AggregateInet6Route>;
|