LCOV - code coverage report
Current view: top level - bgp/routing-instance - route_aggregator.cc (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 469 475 98.7 %
Date: 2026-11-09 02:10:49 Functions: 133 146 91.1 %
Legend: Lines: hit not hit

          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>;

Generated by: LCOV version 1.14