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: 0 475 0.0 %
Date: 2026-09-21 02:11:39 Functions: 0 146 0.0 %
Legend: Lines: hit not hit

          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           0 :     RouteAggregatorState() : contributor_(false), aggregator_(false) {
      33           0 :     }
      34             : 
      35           0 :     void set_aggregating_info(AggregateRoutePtr aggregator) {
      36           0 :         assert(!aggregating_info_);
      37           0 :         aggregating_info_ = aggregator;
      38           0 :         aggregator_ = true;
      39           0 :     }
      40             : 
      41           0 :     void reset_aggregating_info() {
      42           0 :         assert(aggregating_info_);
      43           0 :         aggregating_info_ = NULL;
      44           0 :         aggregator_ = false;
      45           0 :     }
      46             : 
      47           0 :     void set_contributing_info(AggregateRoutePtr aggregator) {
      48           0 :         assert(!contributing_info_);
      49           0 :         contributing_info_ = aggregator;
      50           0 :         contributor_ = true;
      51           0 :     }
      52             : 
      53           0 :     void reset_contributing_info() {
      54           0 :         assert(contributing_info_);
      55           0 :         contributing_info_ = NULL;
      56           0 :         contributor_ = false;
      57           0 :     }
      58             : 
      59             :     AggregateRoutePtr contributing_info() {
      60             :         return contributing_info_;
      61             :     }
      62             : 
      63             :     AggregateRoutePtr aggregating_info() {
      64             :         return aggregating_info_;
      65             :     }
      66             : 
      67           0 :     bool contributor() const {
      68           0 :         return contributor_;
      69             :     }
      70             : 
      71           0 :     bool aggregator() const {
      72           0 :         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           0 :     virtual ~AggregateRoute() {
     104           0 :         assert(!HasContributingRoutes());
     105           0 :     }
     106             : 
     107           0 :     Address::Family GetFamily() const { return manager_->GetFamily(); }
     108           0 :     AddressT GetAddress(IpAddress addr) const {
     109           0 :         return manager_->GetAddress(addr);
     110             :     }
     111             : 
     112             :     // Compare config and return whether cfg has updated
     113             :     CompareResult CompareConfig(const AggregateRouteConfig &cfg);
     114             : 
     115           0 :     const PrefixT &aggregate_route_prefix() const {
     116           0 :         return aggregate_route_prefix_;
     117             :     }
     118             : 
     119           0 :     RoutingInstance *routing_instance() const {
     120           0 :         return routing_instance_;
     121             :     }
     122             : 
     123           0 :     BgpTable *bgp_table() const {
     124           0 :         return routing_instance_->GetTable(this->GetFamily());
     125             :     }
     126             : 
     127           0 :     BgpRoute *aggregate_route() const {
     128           0 :         return aggregate_route_;
     129             :     }
     130             : 
     131           0 :     IpAddress nexthop() const {
     132           0 :         return nexthop_;
     133             :     }
     134             : 
     135           0 :     bool IsMoreSpecific(BgpRoute *route) const {
     136           0 :         const RouteT *ip_route = static_cast<RouteT *>(route);
     137           0 :         const PrefixT &ip_prefix = ip_route->GetPrefix();
     138           0 :         if (ip_prefix.addr() != GetAddress(nexthop()) &&
     139           0 :             ip_prefix != aggregate_route_prefix_ &&
     140           0 :             ip_prefix.IsMoreSpecific(aggregate_route_prefix_)) {
     141           0 :             return true;
     142             :         }
     143           0 :         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           0 :     void UpdateNexthop(IpAddress nexthop) {
     153           0 :         nexthop_ = nexthop;
     154           0 :         UpdateAggregateRoute();
     155           0 :     }
     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           0 :     const ContributingRouteList &contribute_route_list() const {
     173           0 :         return contributors_;
     174             :     }
     175             : 
     176           0 :     bool HasContributingRoutes() const {
     177           0 :         BOOST_FOREACH(RouteList per_part_contributor, contribute_route_list()) {
     178           0 :             if (!per_part_contributor.empty()) {
     179           0 :                 return true;
     180             :             }
     181             :         }
     182           0 :         return false;
     183             :     }
     184             : 
     185           0 :     bool IsContributingRoute(BgpRoute *route) const {
     186           0 :         uint32_t part_id = route->get_table_partition()->index();
     187           0 :         return (contributors_[part_id].find(route) !=
     188           0 :                 contributors_[part_id].end());
     189             :     }
     190             : 
     191           0 :     void NotifyContributingRoute(BgpRoute *route) {
     192           0 :         DBRequest req;
     193           0 :         req.oper = DBRequest::DB_ENTRY_NOTIFY;
     194           0 :         RouteT *ip_route = static_cast<RouteT *>(route);
     195           0 :         const PrefixT &prefix = ip_route->GetPrefix();
     196           0 :         req.key.reset(new typename TableT::RequestKey(prefix, NULL));
     197           0 :         bgp_table()->Enqueue(&req);
     198           0 :     }
     199             : 
     200           0 :     RouteAggregatorState *LocateRouteState(BgpRoute *route) {
     201             :         RouteAggregatorState *state = static_cast<RouteAggregatorState *>
     202           0 :             (route->GetState(bgp_table(), manager_->listener_id()));
     203           0 :         if (state == NULL) {
     204           0 :             state = new RouteAggregatorState();
     205           0 :             route->SetState(bgp_table(), manager_->listener_id(), state);
     206             :         }
     207           0 :         return state;
     208             :     }
     209             : 
     210           0 :     bool AddContributingRoute(BgpRoute *route) {
     211           0 :         uint32_t part_id = route->get_table_partition()->index();
     212           0 :         contributors_[part_id].insert(route);
     213           0 :         RouteAggregatorState *state = LocateRouteState(route);
     214           0 :         state->set_contributing_info(AggregateRoutePtr(this));
     215           0 :         NotifyContributingRoute(route);
     216           0 :         return (contributors_[part_id].size() == 1);
     217             :     }
     218             : 
     219           0 :     void ClearRouteState(BgpRoute *route, RouteAggregatorState *state) {
     220           0 :         if (!state->aggregator() && !state->contributor()) {
     221           0 :             route->ClearState(bgp_table(), manager_->listener_id());
     222           0 :             delete state;
     223             :         }
     224           0 :     }
     225             : 
     226           0 :     bool RemoveContributingRoute(BgpRoute *route) {
     227           0 :         uint32_t part_id = route->get_table_partition()->index();
     228           0 :         int num_deleted = contributors_[part_id].erase(route);
     229             :         RouteAggregatorState *state = static_cast<RouteAggregatorState *>
     230           0 :             (route->GetState(bgp_table(), manager_->listener_id()));
     231           0 :         if (state) {
     232           0 :             state->reset_contributing_info();
     233           0 :             ClearRouteState(route, state);
     234           0 :             NotifyContributingRoute(route);
     235             :         } else {
     236           0 :             assert(num_deleted != 1);
     237             :         }
     238           0 :         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           0 : AggregateRoute<T>::AggregateRoute(RoutingInstance *rtinstance,
     256             :     AggregateRouteMgrT *manager, const PrefixT &aggregate_route,
     257             :     IpAddress nexthop)
     258           0 :     : routing_instance_(rtinstance),
     259           0 :       manager_(manager),
     260           0 :       aggregate_route_prefix_(aggregate_route),
     261           0 :       nexthop_(nexthop),
     262           0 :       aggregate_route_(NULL),
     263           0 :       contributors_(ContributingRouteList(DB::PartitionCount())) {
     264           0 : }
     265             : 
     266             : // Compare config and return whether cfg has updated
     267             : template <typename T>
     268           0 : typename AggregateRoute<T>::CompareResult AggregateRoute<T>::CompareConfig(
     269             :     const AggregateRouteConfig &cfg) {
     270           0 :     AddressT address = this->GetAddress(cfg.aggregate);
     271           0 :     PrefixT prefix(address, cfg.prefix_length);
     272           0 :     assert(aggregate_route_prefix_ == prefix);
     273           0 :     if (nexthop_ != cfg.nexthop) {
     274           0 :         return NexthopChange;
     275             :     }
     276           0 :     return NoChange;
     277             : }
     278             : 
     279             : template <typename T>
     280           0 : bool AggregateRoute<T>::IsOriginVnMatch(BgpRoute *route) const {
     281           0 :     const BgpPath *path = route->BestPath();
     282           0 :     const BgpAttr *attr = path->GetAttr();
     283           0 :     const ExtCommunity *ext_community = attr->ext_community();
     284           0 :     int vni = 0;
     285           0 :     if (ext_community) {
     286           0 :         BOOST_FOREACH(const ExtCommunity::ExtCommunityValue &comm,
     287             :                       ext_community->communities()) {
     288           0 :             if (!ExtCommunity::is_origin_vn(comm)) continue;
     289           0 :             OriginVn origin_vn(comm);
     290           0 :             vni = origin_vn.vn_index();
     291           0 :             break;
     292             :         }
     293             :     }
     294             : 
     295           0 :     if (!vni && path->IsVrfOriginated())
     296           0 :         vni = routing_instance()->virtual_network_index();
     297             : 
     298           0 :     if (vni == routing_instance()->GetOriginVnForAggregateRoute(GetFamily()))
     299           0 :         return true;
     300             : 
     301           0 :     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           0 : bool AggregateRoute<T>::IsBestMatch(BgpRoute *route) const {
     313           0 :     const RouteT *ip_route = static_cast<RouteT *>(route);
     314           0 :     const PrefixT &ip_prefix = ip_route->GetPrefix();
     315           0 :     typename RouteAggregator<T>::AggregateRouteMap::const_iterator it;
     316           0 :     std::set<PrefixT> prefix_list;
     317           0 :     for (it = manager_->aggregate_route_map().begin();
     318           0 :          it != manager_->aggregate_route_map().end(); ++it) {
     319           0 :         if (!it->second->deleted() && ip_prefix != it->first &&
     320           0 :             ip_prefix.IsMoreSpecific(it->first)) {
     321           0 :             prefix_list.insert(it->first);
     322             :         }
     323             :     }
     324             :     // It should match atleast one prefix
     325           0 :     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           0 :     if (*(prefix_list.rbegin()) == aggregate_route_prefix_) return true;
     332           0 :     return false;
     333           0 : }
     334             : 
     335             : // Match function called from BgpConditionListener
     336             : // Concurrency : db::DBTable
     337             : template <typename T>
     338           0 : bool AggregateRoute<T>::Match(BgpServer *server, BgpTable *table,
     339             :                    BgpRoute *route, bool deleted) {
     340           0 :     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           0 :     if ((!deleted && !IsOriginVnMatch(route)) || !IsMoreSpecific(route))
     349           0 :         return false;
     350             : 
     351           0 :     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           0 :         if (IsContributingRoute(route)) {
     359           0 :             if (!IsBestMatch(route)) deleted = true;
     360           0 :         } 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           0 :             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           0 :     if (!deleted && !IsBestMatch(route)) return false;
     376             : 
     377           0 :     BgpConditionListener *listener = server->condition_listener(GetFamily());
     378           0 :     bool state_added = listener->CheckMatchState(table, route, this);
     379           0 :     bool trigger_eval = false;
     380           0 :     if (!deleted) {
     381           0 :         if (!state_added) {
     382           0 :             listener->SetMatchState(table, route, this);
     383           0 :             trigger_eval = AddContributingRoute(route);
     384             :         }
     385             :     } else {
     386           0 :         if (!state_added) {
     387             :             // Not seen ADD ignore DELETE
     388           0 :             return false;
     389             :         }
     390           0 :         trigger_eval = RemoveContributingRoute(route);
     391           0 :         listener->RemoveMatchState(table, route, this);
     392             :     }
     393             : 
     394           0 :     if (trigger_eval) manager_->EvaluateAggregateRoute(this);
     395           0 :     return true;
     396             : }
     397             : 
     398             : // AddAggregateRoute
     399             : template <typename T>
     400           0 : void AggregateRoute<T>::AddAggregateRoute() {
     401           0 :     CHECK_CONCURRENCY("bgp::RouteAggregation");
     402             : 
     403           0 :     RouteT rt_key(aggregate_route_prefix());
     404             :     DBTablePartition *partition =
     405           0 :        static_cast<DBTablePartition *>(bgp_table()->GetTablePartition(&rt_key));
     406             :     BgpRoute *aggregate_route =
     407           0 :         static_cast<BgpRoute *>(partition->Find(&rt_key));
     408             : 
     409           0 :     if (aggregate_route == NULL) {
     410           0 :         aggregate_route = new RouteT(aggregate_route_prefix());
     411           0 :         partition->Add(aggregate_route);
     412             :     } else {
     413           0 :         aggregate_route->ClearDelete();
     414             :     }
     415             : 
     416           0 :     BgpPath *existing_path = aggregate_route->FindPath(BgpPath::Aggregate, 0);
     417           0 :     assert(existing_path == NULL);
     418             : 
     419           0 :     BgpAttrSpec attrs;
     420           0 :     BgpAttrNextHop attr_nexthop(this->GetAddress(nexthop()));
     421           0 :     attrs.push_back(&attr_nexthop);
     422           0 :     ExtCommunitySpec extcomm_spec;
     423           0 :     OriginVn origin_vn(routing_instance()->server()->autonomous_system(),
     424           0 :         routing_instance()->GetOriginVnForAggregateRoute(GetFamily()));
     425           0 :     extcomm_spec.communities.push_back(origin_vn.GetExtCommunityValue());
     426           0 :     attrs.push_back(&extcomm_spec);
     427           0 :     BgpAttrPtr attr = routing_instance()->server()->attr_db()->Locate(attrs);
     428           0 :     BgpPath *new_path = new BgpPath(BgpPath::Aggregate,
     429             :                                     attr.get(), BgpPath::ResolveNexthop, 0);
     430           0 :     bgp_table()->path_resolver()->StartPathResolution(aggregate_route,
     431             :                                                       new_path);
     432           0 :     aggregate_route->InsertPath(new_path);
     433           0 :     partition->Notify(aggregate_route);
     434           0 :     set_aggregate_route(aggregate_route);
     435             : 
     436           0 :     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           0 : }
     440             : 
     441             : // UpdateAggregateRoute
     442             : template <typename T>
     443           0 : void AggregateRoute<T>::UpdateAggregateRoute() {
     444           0 :     CHECK_CONCURRENCY("bgp::Config", "bgp::ConfigHelper");
     445             : 
     446           0 :     if (aggregate_route_ == NULL) return;
     447             : 
     448             :     DBTablePartition *partition = static_cast<DBTablePartition *>
     449           0 :         (bgp_table()->GetTablePartition(aggregate_route_));
     450             : 
     451           0 :     aggregate_route_->ClearDelete();
     452             : 
     453           0 :     BgpPath *existing_path = aggregate_route_->FindPath(BgpPath::Aggregate, 0);
     454           0 :     if (existing_path)
     455           0 :         bgp_table()->path_resolver()->StopPathResolution(partition->index(),
     456             :                                                          existing_path);
     457           0 :     aggregate_route_->RemovePath(BgpPath::Aggregate);
     458             : 
     459           0 :     BgpAttrSpec attrs;
     460           0 :     BgpAttrNextHop attr_nexthop(this->GetAddress(nexthop()));
     461           0 :     attrs.push_back(&attr_nexthop);
     462           0 :     ExtCommunitySpec extcomm_spec;
     463           0 :     OriginVn origin_vn(routing_instance()->server()->autonomous_system(),
     464           0 :         routing_instance()->GetOriginVnForAggregateRoute(GetFamily()));
     465           0 :     extcomm_spec.communities.push_back(origin_vn.GetExtCommunityValue());
     466           0 :     attrs.push_back(&extcomm_spec);
     467           0 :     BgpAttrPtr attr = routing_instance()->server()->attr_db()->Locate(attrs);
     468           0 :     BgpPath *new_path = new BgpPath(BgpPath::Aggregate,
     469             :                                     attr.get(), BgpPath::ResolveNexthop, 0);
     470           0 :     bgp_table()->path_resolver()->StartPathResolution(aggregate_route_,
     471             :                                                       new_path);
     472           0 :     aggregate_route_->InsertPath(new_path);
     473             : 
     474           0 :     partition->Notify(aggregate_route_);
     475             : 
     476           0 :     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           0 : }
     480             : 
     481             : // RemoveAggregateRoute
     482             : template <typename T>
     483           0 : void AggregateRoute<T>::RemoveAggregateRoute() {
     484           0 :     CHECK_CONCURRENCY("bgp::RouteAggregation");
     485           0 :     BgpRoute *aggregate_route = aggregate_route_;
     486           0 :     if (!aggregate_route) return;
     487             : 
     488             :     DBTablePartition *partition = static_cast<DBTablePartition *>
     489           0 :         (bgp_table()->GetTablePartition(aggregate_route_));
     490             : 
     491             :     BgpPath *existing_path =
     492           0 :         aggregate_route->FindPath(BgpPath::Aggregate, 0);
     493           0 :     assert(existing_path != NULL);
     494             : 
     495           0 :     bgp_table()->path_resolver()->StopPathResolution(partition->index(),
     496             :                                                      existing_path);
     497           0 :     aggregate_route->RemovePath(BgpPath::Aggregate);
     498             : 
     499           0 :     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           0 :     if (!aggregate_route->HasPaths()) {
     504           0 :         partition->Delete(aggregate_route);
     505             :     } else {
     506           0 :         partition->Notify(aggregate_route);
     507             :     }
     508           0 :     set_aggregate_route(NULL);
     509             : }
     510             : 
     511             : template <typename T>
     512           0 : void AggregateRoute<T>::set_aggregate_route(BgpRoute *aggregate) {
     513           0 :     if (aggregate) {
     514           0 :         assert(aggregate_route_ == NULL);
     515           0 :         RouteAggregatorState *state = LocateRouteState(aggregate);
     516           0 :         state->set_aggregating_info(AggregateRoutePtr(this));
     517             :     } else {
     518           0 :         assert(aggregate_route_ != NULL);
     519             :         RouteAggregatorState *state = static_cast<RouteAggregatorState *>
     520           0 :             (aggregate_route_->GetState(bgp_table(), manager_->listener_id()));
     521           0 :         assert(state);
     522           0 :         state->reset_aggregating_info();
     523           0 :         ClearRouteState(aggregate_route_, state);
     524             :     }
     525           0 :     aggregate_route_ = aggregate;
     526           0 : }
     527             : 
     528             : template <typename T>
     529           0 : void AggregateRoute<T>::FillShowInfo(AggregateRouteInfo *info,
     530             :     bool summary) const {
     531           0 :     BgpTable *table = bgp_table();
     532           0 :     info->set_deleted(deleted());
     533           0 :     info->set_prefix(aggregate_route_prefix_.ToString());
     534           0 :     if (aggregate_route_) {
     535           0 :         ShowRouteBrief show_route;
     536           0 :         aggregate_route_->FillRouteInfo(table, &show_route);
     537           0 :         info->set_aggregate_rt(show_route);
     538           0 :     }
     539             : 
     540           0 :     info->set_nexthop(nexthop_.to_string());
     541             : 
     542           0 :     if (summary)
     543           0 :         return;
     544             : 
     545           0 :     std::vector<string> contributor_list;
     546           0 :     BOOST_FOREACH(const RouteList &list, contribute_route_list()) {
     547           0 :         BOOST_FOREACH(BgpRoute *rt, list) {
     548           0 :             contributor_list.push_back(rt->ToString());
     549             :         }
     550             :     }
     551           0 :     info->set_contributors(contributor_list);
     552           0 : }
     553             : 
     554             : template <typename T>
     555             : class RouteAggregator<T>::DeleteActor : public LifetimeActor {
     556             : public:
     557           0 :     explicit DeleteActor(RouteAggregator *aggregator) :
     558             :     LifetimeActor(aggregator->routing_instance()->server()->lifetime_manager()),
     559           0 :     aggregator_(aggregator) {
     560           0 :     }
     561           0 :     virtual ~DeleteActor() {
     562           0 :     }
     563             : 
     564           0 :     virtual bool MayDelete() const {
     565           0 :         return aggregator_->MayDelete();
     566             :     }
     567             : 
     568           0 :     virtual void Destroy() {
     569           0 :         aggregator_->routing_instance()->DestroyRouteAggregator(
     570           0 :                                                     aggregator_->GetFamily());
     571           0 :     }
     572             : 
     573             : private:
     574             :     RouteAggregator *aggregator_;
     575             : };
     576             : 
     577             : template <typename T>
     578           0 : RouteAggregator<T>::RouteAggregator(RoutingInstance *rtinstance)
     579           0 :   : rtinstance_(rtinstance),
     580           0 :     condition_listener_(rtinstance_->server()->condition_listener(GetFamily())),
     581           0 :     listener_id_(DBTableBase::kInvalidId),
     582           0 :     update_list_trigger_(new TaskTrigger(
     583             :         boost::bind(&RouteAggregator::ProcessUpdateList, this),
     584           0 :         TaskScheduler::GetInstance()->GetTaskId("bgp::RouteAggregation"),
     585             :         0)),
     586           0 :     unregister_list_trigger_(new TaskTrigger(
     587             :         boost::bind(&RouteAggregator::ProcessUnregisterList, this),
     588           0 :         TaskScheduler::GetInstance()->GetTaskId("bgp::Config"), 0)),
     589           0 :     deleter_(new DeleteActor(this)),
     590           0 :     instance_delete_ref_(this, rtinstance->deleter()) {
     591           0 : }
     592             : 
     593             : template <typename T>
     594           0 : RouteAggregator<T>::~RouteAggregator() {
     595           0 :     if (listener_id_ != DBTableBase::kInvalidId)
     596           0 :         bgp_table()->Unregister(listener_id_);
     597           0 :     listener_id_ = DBTableBase::kInvalidId;
     598           0 : }
     599             : 
     600             : template <typename T>
     601           0 : void RouteAggregator<T>::ProcessAggregateRouteConfig() {
     602           0 :     CHECK_CONCURRENCY("bgp::Config", "bgp::ConfigHelper");
     603             :     const AggregateRouteConfigList &list =
     604           0 :         routing_instance()->config()->aggregate_routes(GetFamily());
     605             :     typedef AggregateRouteConfigList::const_iterator iterator_t;
     606           0 :     for (iterator_t iter = list.begin(); iter != list.end(); ++iter) {
     607           0 :         LocateAggregateRoutePrefix(*iter);
     608             :     }
     609           0 : }
     610             : 
     611           0 : bool CompareAggregateRouteConfig(const AggregateRouteConfig &lhs,
     612             :                                  const AggregateRouteConfig &rhs) {
     613           0 :     BOOL_KEY_COMPARE(lhs.aggregate, rhs.aggregate);
     614           0 :     BOOL_KEY_COMPARE(lhs.prefix_length, rhs.prefix_length);
     615           0 :     return false;
     616             : }
     617             : 
     618             : template <typename T>
     619           0 : void RouteAggregator<T>::UpdateAggregateRouteConfig() {
     620           0 :     CHECK_CONCURRENCY("bgp::Config", "bgp::ConfigHelper");
     621           0 :     AggregateRouteConfigList config_list =
     622           0 :         routing_instance()->config()->aggregate_routes(GetFamily());
     623           0 :     sort(config_list.begin(), config_list.end(), CompareAggregateRouteConfig);
     624             : 
     625           0 :     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           0 : }
     632             : 
     633             : template <typename T>
     634           0 : void RouteAggregator<T>::FlushAggregateRouteConfig() {
     635           0 :     CHECK_CONCURRENCY("bgp::Config");
     636           0 :     for (typename AggregateRouteMap::iterator it = aggregate_route_map_.begin();
     637           0 :          it != aggregate_route_map_.end(); it++) {
     638           0 :         RemoveAggregateRoutePrefix(it->first);
     639             :     }
     640           0 : }
     641             : 
     642             : template <>
     643           0 : Address::Family RouteAggregator<AggregateInetRoute>::GetFamily() const {
     644           0 :     return Address::INET;
     645             : }
     646             : 
     647             : template <>
     648           0 : Address::Family RouteAggregator<AggregateInet6Route>::GetFamily() const {
     649           0 :     return Address::INET6;
     650             : }
     651             : 
     652             : template <>
     653           0 : Ip4Address RouteAggregator<AggregateInetRoute>::GetAddress(IpAddress addr)
     654             :     const {
     655           0 :     assert(addr.is_v4());
     656           0 :     return addr.to_v4();
     657             : }
     658             : 
     659             : template <>
     660           0 : Ip6Address RouteAggregator<AggregateInet6Route>::GetAddress(IpAddress addr)
     661             :     const {
     662           0 :     assert(addr.is_v6());
     663           0 :     return addr.to_v6();
     664             : }
     665             : 
     666             : template <typename T>
     667           0 : BgpTable *RouteAggregator<T>::bgp_table() const {
     668           0 :     return rtinstance_->GetTable(GetFamily());
     669             : }
     670             : 
     671             : template <typename T>
     672           0 : void RouteAggregator<T>::Initialize() {
     673             :     // Register to the table before adding first match condition
     674           0 :     listener_id_ = bgp_table()->Register(
     675             :          boost::bind(&RouteAggregator::RouteListener, this, _1, _2),
     676             :          "RouteAggregator");
     677           0 : }
     678             : 
     679             : template <typename T>
     680           0 : bool RouteAggregator<T>::MayDelete() const {
     681           0 :     if (!aggregate_route_map_.empty())
     682           0 :         return false;
     683           0 :     if (!update_aggregate_list_.empty())
     684           0 :         return false;
     685           0 :     if (!unregister_aggregate_list_.empty())
     686           0 :         return false;
     687           0 :     return true;
     688             : }
     689             : 
     690             : // Cascade delete from RoutingInstance delete_ref to self.
     691             : template <typename T>
     692           0 : void RouteAggregator<T>::ManagedDelete() {
     693           0 :     deleter_->Delete();
     694           0 : }
     695             : 
     696             : // Attempt to enqueue a delete for the RouteAggregator.
     697             : template <typename T>
     698           0 : void RouteAggregator<T>::RetryDelete() {
     699           0 :     if (!deleter_->IsDeleted())
     700           0 :         return;
     701           0 :     deleter_->RetryDelete();
     702             : }
     703             : 
     704             : template <typename T>
     705           0 : void RouteAggregator<T>::EvaluateAggregateRoute(AggregateRoutePtr entry) {
     706           0 :     std::scoped_lock lock(mutex_);
     707           0 :     update_aggregate_list_.insert(entry);
     708           0 :     update_list_trigger_->Set();
     709           0 : }
     710             : 
     711             : template <typename T>
     712           0 : void RouteAggregator<T>::UnregisterAndResolveRouteAggregate(
     713             :                                                     AggregateRoutePtr entry) {
     714           0 :     std::scoped_lock lock(mutex_);
     715           0 :     unregister_aggregate_list_.insert(entry);
     716           0 :     unregister_list_trigger_->Set();
     717           0 : }
     718             : 
     719             : template <typename T>
     720           0 : bool RouteAggregator<T>::IsAggregateRoute(const BgpRoute *route) const {
     721             :     RouteAggregatorState *state = static_cast<RouteAggregatorState *>
     722           0 :         (route->GetState(bgp_table(), listener_id()));
     723           0 :     if (state) {
     724           0 :         return (state->aggregator());
     725             :     }
     726           0 :     return false;
     727             : }
     728             : 
     729             : template <typename T>
     730           0 : bool RouteAggregator<T>::IsContributingRoute(const BgpRoute *route) const {
     731             :     RouteAggregatorState *state = static_cast<RouteAggregatorState *>
     732           0 :         (route->GetState(bgp_table(), listener_id()));
     733           0 :     if (state) {
     734           0 :         return state->contributor();
     735             :     }
     736           0 :     return false;
     737             : }
     738             : 
     739             : template <typename T>
     740           0 : bool RouteAggregator<T>::FillAggregateRouteInfo(AggregateRouteEntriesInfo *info,
     741             :     bool summary) const {
     742           0 :     if (aggregate_route_map().empty())
     743           0 :         return false;
     744             : 
     745           0 :     info->set_name(rtinstance_->GetVirtualNetworkName());
     746           0 :     info->set_instance_name(rtinstance_->name());
     747           0 :     vector<AggregateRouteInfo> aggregate_route_list =
     748             :         vector<AggregateRouteInfo>();
     749           0 :     for (typename AggregateRouteMap::const_iterator it =
     750           0 :          aggregate_route_map_.begin(); it != aggregate_route_map_.end(); it++) {
     751             :         AggregateRouteT *aggregate =
     752           0 :             static_cast<AggregateRouteT *>(it->second.get());
     753           0 :         AggregateRouteInfo aggregate_info;
     754           0 :         aggregate->FillShowInfo(&aggregate_info, summary);
     755           0 :         aggregate_route_list.push_back(aggregate_info);
     756             :     }
     757           0 :     info->set_aggregate_route_list(aggregate_route_list);
     758           0 :     return true;
     759           0 : }
     760             : 
     761             : template <typename T>
     762           0 : int RouteAggregator<T>::CompareAggregateRoute(
     763             :     typename AggregateRouteMap::iterator loc,
     764             :     AggregateRouteConfigList::iterator it) {
     765           0 :     AddressT address = this->GetAddress(it->aggregate);
     766           0 :     PrefixT prefix(address, it->prefix_length);
     767           0 :     KEY_COMPARE(loc->first, prefix);
     768           0 :     return 0;
     769             : }
     770             : 
     771             : template <typename T>
     772           0 : void RouteAggregator<T>::AddAggregateRoute(
     773             :     AggregateRouteConfigList::iterator it) {
     774           0 :     LocateAggregateRoutePrefix(*it);
     775           0 : }
     776             : 
     777             : template <typename T>
     778           0 : void RouteAggregator<T>::DelAggregateRoute(
     779             :     typename AggregateRouteMap::iterator loc) {
     780           0 :     RemoveAggregateRoutePrefix(loc->first);
     781           0 : }
     782             : 
     783             : template <typename T>
     784           0 : void RouteAggregator<T>::UpdateAggregateRoute(
     785             :     typename AggregateRouteMap::iterator loc,
     786             :     AggregateRouteConfigList::iterator it) {
     787           0 :     LocateAggregateRoutePrefix(*it);
     788           0 : }
     789             : 
     790             : template <typename T>
     791           0 : void RouteAggregator<T>::LocateAggregateRoutePrefix(const AggregateRouteConfig
     792             :                                                     &cfg) {
     793           0 :     CHECK_CONCURRENCY("bgp::Config", "bgp::ConfigHelper");
     794           0 :     AddressT address = this->GetAddress(cfg.aggregate);
     795           0 :     PrefixT prefix(address, cfg.prefix_length);
     796             : 
     797             :     // Verify whether the entry already exists
     798           0 :     typename AggregateRouteMap::iterator it = aggregate_route_map_.find(prefix);
     799           0 :     if (it != aggregate_route_map_.end()) {
     800             :         // Wait for the delete complete cb
     801           0 :         if (it->second->deleted()) return;
     802             : 
     803             :         AggregateRouteT *match =
     804           0 :             static_cast<AggregateRouteT *>(it->second.get());
     805             :         // Check whether the config has got updated
     806             :         typename AggregateRouteT::CompareResult change =
     807           0 :             match->CompareConfig(cfg);
     808             :         // No change..
     809           0 :         if (change == AggregateRouteT::NoChange) return;
     810             : 
     811           0 :         if (change == AggregateRouteT::NexthopChange)
     812           0 :             match->UpdateNexthop(cfg.nexthop);
     813           0 :         return;
     814             :     }
     815             : 
     816           0 :     AggregateRouteT *match =
     817           0 :         new AggregateRouteT(routing_instance(), this, prefix, cfg.nexthop);
     818           0 :     AggregateRoutePtr aggregate_route_match = AggregateRoutePtr(match);
     819           0 :     aggregate_route_map_.insert(make_pair(prefix, aggregate_route_match));
     820             : 
     821           0 :     condition_listener_->AddMatchCondition(match->bgp_table(),
     822           0 :            aggregate_route_match.get(), BgpConditionListener::RequestDoneCb());
     823           0 :     return;
     824           0 : }
     825             : 
     826             : template <typename T>
     827           0 : void RouteAggregator<T>::RemoveAggregateRoutePrefix(const PrefixT &aggregate) {
     828           0 :     CHECK_CONCURRENCY("bgp::Config", "bgp::ConfigHelper");
     829             :     typename AggregateRouteMap::iterator it =
     830           0 :         aggregate_route_map_.find(aggregate);
     831           0 :     if (it == aggregate_route_map_.end()) return;
     832           0 :     if (it->second->deleted()) return;
     833             : 
     834           0 :     BgpConditionListener::RequestDoneCb callback =
     835             :         boost::bind(&RouteAggregator::StopAggregateRouteDone, this, _1, _2);
     836             : 
     837           0 :     AggregateRouteT *match = static_cast<AggregateRouteT *>(it->second.get());
     838           0 :     condition_listener_->RemoveMatchCondition(match->bgp_table(),
     839             :                                               match, callback);
     840           0 : }
     841             : 
     842             : template <typename T>
     843           0 : void RouteAggregator<T>::StopAggregateRouteDone(BgpTable *table,
     844             :                                              ConditionMatch *info) {
     845           0 :     CHECK_CONCURRENCY("db::Walker");
     846           0 :     UnregisterAndResolveRouteAggregate(info);
     847           0 :     return;
     848             : }
     849             : 
     850             : template <typename T>
     851           0 : bool RouteAggregator<T>::ProcessUnregisterList() {
     852           0 :     CHECK_CONCURRENCY("bgp::Config");
     853             : 
     854           0 :     for (AggregateRouteProcessList::iterator
     855           0 :          it = unregister_aggregate_list_.begin();
     856           0 :          it != unregister_aggregate_list_.end(); ++it) {
     857           0 :         AggregateRouteT *aggregate = static_cast<AggregateRouteT *>(it->get());
     858           0 :         aggregate_route_map_.erase(aggregate->aggregate_route_prefix());
     859           0 :         condition_listener_->UnregisterMatchCondition(aggregate->bgp_table(),
     860             :                                                       aggregate);
     861             :     }
     862             : 
     863           0 :     unregister_aggregate_list_.clear();
     864             : 
     865           0 :     if (!routing_instance()->deleted() && routing_instance()->config())
     866           0 :         ProcessAggregateRouteConfig();
     867             : 
     868           0 :     if (MayDelete()) RetryDelete();
     869           0 :     return true;
     870             : }
     871             : 
     872             : template <typename T>
     873           0 : bool RouteAggregator<T>::ProcessUpdateList() {
     874           0 :     CHECK_CONCURRENCY("bgp::RouteAggregation");
     875             : 
     876           0 :     for (AggregateRouteProcessList::iterator
     877           0 :          it = update_aggregate_list_.begin();
     878           0 :          it != update_aggregate_list_.end(); ++it) {
     879           0 :         AggregateRouteT *aggregate = static_cast<AggregateRouteT *>(it->get());
     880           0 :         if (aggregate->aggregate_route()) {
     881           0 :             if (!aggregate->HasContributingRoutes())
     882           0 :                 aggregate->RemoveAggregateRoute();
     883             :         } else {
     884           0 :             if (aggregate->HasContributingRoutes())
     885           0 :                 aggregate->AddAggregateRoute();
     886             :         }
     887             :     }
     888             : 
     889           0 :     update_aggregate_list_.clear();
     890             : 
     891           0 :     if (MayDelete()) RetryDelete();
     892           0 :     return true;
     893             : }
     894             : 
     895             : // Need this to store the aggregate info in aggregated route as DBState
     896             : template <typename T>
     897           0 : bool RouteAggregator<T>::RouteListener(DBTablePartBase *root,
     898             :                                        DBEntryBase *entry) {
     899           0 :     return true;
     900             : }
     901             : 
     902             : // Enable/Disable task triggers
     903             : template <typename T>
     904           0 : void RouteAggregator<T>::DisableRouteAggregateUpdate() {
     905           0 :     update_list_trigger_->set_disable();
     906           0 : }
     907             : 
     908             : template <typename T>
     909           0 : void RouteAggregator<T>::EnableRouteAggregateUpdate() {
     910           0 :     update_list_trigger_->set_enable();
     911           0 : }
     912             : 
     913             : template <typename T>
     914           0 : size_t RouteAggregator<T>::GetUpdateAggregateListSize() const {
     915           0 :     return update_aggregate_list_.size();
     916             : }
     917             : 
     918             : template <typename T>
     919           0 : void RouteAggregator<T>::DisableUnregResolveTask() {
     920           0 :     unregister_list_trigger_->set_disable();
     921           0 : }
     922             : 
     923             : template <typename T>
     924           0 : void RouteAggregator<T>::EnableUnregResolveTask() {
     925           0 :     unregister_list_trigger_->set_enable();
     926           0 : }
     927             : 
     928             : template <typename T>
     929           0 : size_t RouteAggregator<T>::GetUnregResolveListSize() const {
     930           0 :     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>;

Generated by: LCOV version 1.14