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

Generated by: LCOV version 1.14