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