LCOV - code coverage report
Current view: top level - bgp/routing-instance - static_route.cc (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 0 477 0.0 %
Date: 2026-09-21 02:11:39 Functions: 0 105 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
       3             :  */
       4             : 
       5             : #include "bgp/routing-instance/static_route.h"
       6             : 
       7             : #include <boost/assign/list_of.hpp>
       8             : #include <boost/foreach.hpp>
       9             : 
      10             : #include <algorithm>
      11             : #include <string>
      12             : #include <vector>
      13             : 
      14             : #include "base/map_util.h"
      15             : #include "base/task_annotations.h"
      16             : #include "base/task_trigger.h"
      17             : #include "bgp/bgp_config.h"
      18             : #include "bgp/bgp_log.h"
      19             : #include "bgp/bgp_server.h"
      20             : #include "bgp/inet6vpn/inet6vpn_route.h"
      21             : #include "bgp/l3vpn/inetvpn_route.h"
      22             : #include "bgp/origin-vn/origin_vn.h"
      23             : #include "bgp/routing-instance/routepath_replicator.h"
      24             : #include "bgp/routing-instance/routing_instance.h"
      25             : #include "bgp/routing-instance/static_route_types.h"
      26             : #include "bgp/routing-policy/routing_policy_match.h"
      27             : #include "net/community_type.h"
      28             : 
      29             : using boost::assign::list_of;
      30             : using boost::system::error_code;
      31             : using std::make_pair;
      32             : using std::set;
      33             : using std::string;
      34             : using std::vector;
      35             : 
      36             : class StaticRouteState : public ConditionMatchState {
      37             : public:
      38           0 :     explicit StaticRouteState(StaticRoutePtr info) : info_(info) {
      39           0 :     }
      40             :     StaticRoutePtr info() {
      41             :         return info_;
      42             :     }
      43             : 
      44             : private:
      45             :     StaticRoutePtr info_;
      46             :     DISALLOW_COPY_AND_ASSIGN(StaticRouteState);
      47             : };
      48             : 
      49             : template <typename T>
      50             : class StaticRoute : public ConditionMatch {
      51             : public:
      52             :     typedef typename T::RouteT RouteT;
      53             :     typedef typename T::VpnRouteT VpnRouteT;
      54             :     typedef typename T::PrefixT PrefixT;
      55             :     typedef typename T::AddressT AddressT;
      56             :     typedef StaticRouteMgr<T> StaticRouteMgrT;
      57             : 
      58             :     // List of Route targets
      59             :     typedef set<RouteTarget> RouteTargetList;
      60             : 
      61             :     // List of path ids for the Nexthop
      62             :     typedef set<uint32_t> NexthopPathIdList;
      63             : 
      64             :     enum CompareResult {
      65             :         NoChange = 0,
      66             :         PrefixChange = 1,
      67             :         NexthopChange = 2,
      68             :         AttributeChange = 3
      69             :     };
      70             : 
      71             :     StaticRoute(RoutingInstance *rtinstance, StaticRouteMgrT *manager,
      72             :         const PrefixT &static_route, const StaticRouteConfig &config);
      73           0 :     Address::Family GetFamily() const { return manager_->GetFamily(); }
      74           0 :     AddressT GetAddress(IpAddress addr) const {
      75           0 :         return manager_->GetAddress(addr);
      76             :     }
      77             : 
      78             :     CompareResult CompareConfig(const StaticRouteConfig &config);
      79             :     void FillShowInfo(StaticRouteInfo *info) const;
      80             : 
      81           0 :     const PrefixT &prefix() const {
      82           0 :         return prefix_;
      83             :     }
      84             : 
      85           0 :     const IpAddress &nexthop() const {
      86           0 :         return nexthop_;
      87             :     }
      88             : 
      89           0 :     RoutingInstance *routing_instance() const {
      90           0 :         return routing_instance_;
      91             :     }
      92             : 
      93           0 :     BgpTable *bgp_table() const {
      94           0 :         return routing_instance_->GetTable(this->GetFamily());
      95             :     }
      96             : 
      97           0 :     BgpRoute *nexthop_route() const {
      98           0 :         return nexthop_route_;
      99             :     }
     100             : 
     101           0 :     NexthopPathIdList *NexthopPathIds() { return &nexthop_path_ids_; }
     102             : 
     103           0 :     void set_nexthop_route(BgpRoute *nexthop_route) {
     104           0 :         nexthop_route_ = nexthop_route;
     105             : 
     106           0 :         if (!nexthop_route_) {
     107           0 :             nexthop_path_ids_.clear();
     108           0 :             return;
     109             :         }
     110             : 
     111           0 :         assert(nexthop_path_ids_.empty());
     112             : 
     113           0 :         for (Route::PathList::iterator it =
     114           0 :              nexthop_route->GetPathList().begin();
     115           0 :              it != nexthop_route->GetPathList().end(); it++) {
     116           0 :             BgpPath *path = static_cast<BgpPath *>(it.operator->());
     117             : 
     118             :             // Infeasible paths are not considered
     119           0 :             if (!path->IsFeasible()) break;
     120             : 
     121             :             // take snapshot of all ECMP paths
     122           0 :             if (nexthop_route_->BestPath()->PathCompare(*path, true)) break;
     123             : 
     124             :             // Use the nexthop attribute of the nexthop path as the path id.
     125           0 :             uint32_t path_id = path->GetAttr()->nexthop().to_v4().to_ulong();
     126           0 :             nexthop_path_ids_.insert(path_id);
     127             :         }
     128             :     }
     129             : 
     130           0 :     const RouteTargetList &rtarget_list() const {
     131           0 :         return rtarget_list_;
     132             :     }
     133             : 
     134             :     void UpdateAttributes(const StaticRouteConfig &config);
     135             :     void AddStaticRoute(NexthopPathIdList *list);
     136             :     void UpdateStaticRoute();
     137             :     void RemoveStaticRoute();
     138             :     void NotifyRoute();
     139             :     bool IsPending() const;
     140             : 
     141             :     virtual bool Match(BgpServer *server, BgpTable *table,
     142             :                        BgpRoute *route, bool deleted);
     143             : 
     144           0 :     virtual string ToString() const {
     145           0 :         return (string("StaticRoute ") + nexthop_.to_string());
     146             :     }
     147             : 
     148           0 :     void set_unregistered() {
     149           0 :         unregistered_ = true;
     150           0 :     }
     151             : 
     152           0 :     bool unregistered() const {
     153           0 :         return unregistered_;
     154             :     }
     155             : 
     156             : private:
     157             :     // Helper function to match
     158           0 :     bool is_nexthop_route(BgpRoute *route) {
     159           0 :         RouteT *ip_route = dynamic_cast<RouteT *>(route);
     160           0 :         return (nexthop_ == ip_route->GetPrefix().addr());
     161             :     }
     162             : 
     163             :     CommunityPtr GetCommunity(const StaticRouteConfig &config);
     164             :     ExtCommunityPtr UpdateExtCommunity(const BgpAttr *attr) const;
     165             : 
     166             :     RoutingInstance *routing_instance_;
     167             :     StaticRouteMgrT *manager_;
     168             :     PrefixT prefix_;
     169             :     IpAddress nexthop_;
     170             :     BgpRoute *nexthop_route_;
     171             :     NexthopPathIdList nexthop_path_ids_;
     172             :     RouteTargetList rtarget_list_;
     173             :     CommunityPtr community_;
     174             :     bool unregistered_;
     175             : 
     176             :     DISALLOW_COPY_AND_ASSIGN(StaticRoute);
     177             : };
     178             : 
     179             : template <typename T>
     180           0 : StaticRoute<T>::StaticRoute(RoutingInstance *rtinstance,
     181             :     StaticRouteMgrT *manager, const PrefixT &prefix,
     182             :     const StaticRouteConfig &config)
     183           0 :     : routing_instance_(rtinstance),
     184           0 :       manager_(manager),
     185           0 :       prefix_(prefix),
     186           0 :       nexthop_(config.nexthop),
     187           0 :       nexthop_route_(NULL),
     188           0 :       unregistered_(false) {
     189           0 :     UpdateAttributes(config);
     190           0 : }
     191             : 
     192             : //
     193             : // Compare the given config against the current state of the StaticRoute.
     194             : // Return the appropriate value from CompareResult.
     195             : //
     196             : template <typename T>
     197           0 : typename StaticRoute<T>::CompareResult StaticRoute<T>::CompareConfig(
     198             :     const StaticRouteConfig &config) {
     199           0 :     AddressT address = this->GetAddress(config.address);
     200           0 :     PrefixT prefix(address, config.prefix_length);
     201           0 :     if (prefix_ != prefix) {
     202           0 :         return PrefixChange;
     203             :     }
     204           0 :     if (nexthop_ != config.nexthop) {
     205           0 :         return NexthopChange;
     206             :     }
     207           0 :     if (rtarget_list_.size() != config.route_targets.size()) {
     208           0 :         return AttributeChange;
     209             :     }
     210           0 :     for (vector<string>::const_iterator it = config.route_targets.begin();
     211           0 :          it != config.route_targets.end(); ++it) {
     212           0 :         error_code ec;
     213           0 :         RouteTarget rtarget = RouteTarget::FromString(*it, &ec);
     214           0 :         if (rtarget_list_.find(rtarget) == rtarget_list_.end()) {
     215           0 :             return AttributeChange;
     216             :         }
     217             :     }
     218           0 :     if (community_ != GetCommunity(config)) {
     219           0 :         return AttributeChange;
     220             :     }
     221             : 
     222           0 :     return NoChange;
     223             : }
     224             : 
     225             : template <typename T>
     226           0 : void StaticRoute<T>::FillShowInfo(StaticRouteInfo *info) const {
     227           0 :     BgpTable *table = bgp_table();
     228           0 :     RouteT rt_key(prefix_);
     229           0 :     const BgpRoute *route = static_cast<const BgpRoute *>(table->Find(&rt_key));
     230           0 :     const BgpPath *path = route ? route->FindPath(BgpPath::StaticRoute) : NULL;
     231             : 
     232           0 :     info->set_prefix(prefix_.ToString());
     233           0 :     info->set_static_rt(path ? true : false);
     234           0 :     info->set_nexthop(nexthop_.to_string());
     235           0 :     if (nexthop_route_) {
     236           0 :         ShowRouteBrief show_route;
     237           0 :         nexthop_route_->FillRouteInfo(table, &show_route);
     238           0 :         info->set_nexthop_rt(show_route);
     239           0 :     }
     240             : 
     241           0 :     vector<string> community_list;
     242           0 :     BOOST_FOREACH(uint32_t value, community_->communities()) {
     243           0 :         community_list.push_back(CommunityType::CommunityToString(value));
     244             :     }
     245           0 :     info->set_community_list(community_list);
     246             : 
     247           0 :     vector<string> route_target_list;
     248           0 :     for (RouteTargetList::const_iterator it = rtarget_list_.begin();
     249           0 :         it != rtarget_list_.end(); ++it) {
     250           0 :         route_target_list.push_back(it->ToString());
     251             :     }
     252           0 :     info->set_route_target_list(route_target_list);
     253             : 
     254           0 :     if (path) {
     255           0 :         const RoutePathReplicator *replicator = table->server()->replicator(
     256             :             Address::VpnFamilyFromFamily(GetFamily()));
     257           0 :         info->set_secondary_tables(
     258             :             replicator->GetReplicatedTableNameList(table, route, path));
     259             :     }
     260           0 : }
     261             : 
     262             : // Match function called from BgpConditionListener
     263             : // Concurrency : db::DBTable
     264             : template <typename T>
     265           0 : bool StaticRoute<T>::Match(BgpServer *server, BgpTable *table,
     266             :                    BgpRoute *route, bool deleted) {
     267           0 :     CHECK_CONCURRENCY("db::DBTable");
     268             :     StaticRouteRequest::RequestType type;
     269             : 
     270           0 :     if (is_nexthop_route(route) && !unregistered()) {
     271           0 :         if (deleted)
     272           0 :             type = StaticRouteRequest::NEXTHOP_DELETE;
     273             :         else
     274           0 :             type = StaticRouteRequest::NEXTHOP_ADD_CHG;
     275             :     } else {
     276           0 :         return false;
     277             :     }
     278             : 
     279           0 :     BgpConditionListener *listener = server->condition_listener(GetFamily());
     280             :     StaticRouteState *state = static_cast<StaticRouteState *>
     281           0 :         (listener->GetMatchState(table, route, this));
     282           0 :     if (!deleted) {
     283             :         // MatchState is added to the Route to ensure that DBEntry is not
     284             :         // deleted before the module processes the WorkQueue request.
     285           0 :         if (!state) {
     286           0 :             state = new StaticRouteState(StaticRoutePtr(this));
     287           0 :             listener->SetMatchState(table, route, this, state);
     288             :         }
     289             :     } else {
     290             :         // MatchState is set on all the Routes that matches the conditions
     291             :         // Retrieve to check and ignore delete of unseen Add Match
     292           0 :         if (state == NULL) {
     293             :             // Not seen ADD ignore DELETE
     294           0 :             return false;
     295             :         }
     296             :     }
     297             : 
     298             :     // The MatchState reference is taken to ensure that the route is not
     299             :     // deleted when request is still present in the queue
     300             :     // This is to handle the case where MatchState already exists and
     301             :     // deleted entry gets reused or reused entry gets deleted.
     302           0 :     state->IncrementRefCnt();
     303             : 
     304             :     // Post the Match result to StaticRoute processing task to take Action
     305             :     // Nexthop route found in NAT instance ==> Add Static Route
     306             :     // and stitch the Path Attribute from nexthop route
     307           0 :     StaticRouteRequest *req =
     308           0 :         new StaticRouteRequest(type, table, route, StaticRoutePtr(this));
     309           0 :     manager_->EnqueueStaticRouteReq(req);
     310             : 
     311           0 :     return true;
     312             : }
     313             : 
     314             : //
     315             : // Build a Community for the given StaticRouteConfig.
     316             : // Always add the AcceptOwnNexthop community in addition to the configured
     317             : // list.
     318             : //
     319             : template <typename T>
     320           0 : CommunityPtr StaticRoute<T>::GetCommunity(const StaticRouteConfig &config) {
     321           0 :     CommunitySpec comm_spec;
     322           0 :     comm_spec.communities.push_back(CommunityType::AcceptOwnNexthop);
     323           0 :     for (vector<string>::const_iterator it = config.communities.begin();
     324           0 :          it != config.communities.end(); ++it) {
     325           0 :         uint32_t value = CommunityType::CommunityFromString(*it);
     326           0 :         if (!value)
     327           0 :             continue;
     328           0 :         comm_spec.communities.push_back(value);
     329             :     }
     330           0 :     CommunityDB *comm_db = routing_instance()->server()->comm_db();
     331           0 :     return comm_db->Locate(comm_spec);
     332           0 : }
     333             : 
     334             : //
     335             : // Build an updated ExtCommunity for the static route.
     336             : //
     337             : // Replace any RouteTargets with the list of RouteTargets for the StaticRoute.
     338             : // If the StaticRoute has an empty RouteTarget list, then we infer that this
     339             : // is not a snat use case and add the OriginVn as well. We don't want to add
     340             : // OriginVn in snat scenario because the route has to be imported into many
     341             : // VRFs and we want to set the OriginVn differently for each imported route.
     342             : //
     343             : template <typename T>
     344           0 : ExtCommunityPtr StaticRoute<T>::UpdateExtCommunity(const BgpAttr *attr) const {
     345           0 :     ExtCommunity::ExtCommunityList export_list;
     346           0 :     for (RouteTargetList::const_iterator it = rtarget_list().begin();
     347           0 :         it != rtarget_list().end(); it++) {
     348           0 :         export_list.push_back(it->GetExtCommunity());
     349             :     }
     350             : 
     351           0 :     BgpServer *server = routing_instance()->server();
     352           0 :     ExtCommunityDB *extcomm_db = server->extcomm_db();
     353           0 :     ExtCommunityPtr new_ext_community = extcomm_db->ReplaceRTargetAndLocate(
     354             :         attr->ext_community(), export_list);
     355             : 
     356           0 :     int vn_index = routing_instance()->virtual_network_index();
     357           0 :     if (export_list.empty() && vn_index) {
     358           0 :         as_t asn = server->autonomous_system();
     359           0 :         if (asn > AS2_MAX && vn_index > 0xffff) {
     360           0 :             OriginVn origin_vn(asn, AS_TRANS);
     361           0 :             new_ext_community = extcomm_db->ReplaceOriginVnAndLocate(
     362           0 :                 new_ext_community.get(), origin_vn.GetExtCommunity());
     363           0 :             OriginVn origin_vn2(AS_TRANS, vn_index);
     364           0 :             new_ext_community = extcomm_db->AppendAndLocate(
     365           0 :                 new_ext_community.get(), origin_vn2.GetExtCommunity());
     366           0 :         } else {
     367           0 :             OriginVn origin_vn(server->autonomous_system(), vn_index);
     368           0 :             new_ext_community = extcomm_db->ReplaceOriginVnAndLocate(
     369           0 :                 new_ext_community.get(), origin_vn.GetExtCommunity());
     370             :         }
     371             :     }
     372           0 :     return new_ext_community;
     373           0 : }
     374             : 
     375             : template <typename T>
     376           0 : void StaticRoute<T>::UpdateAttributes(const StaticRouteConfig &config) {
     377           0 :     rtarget_list_.clear();
     378           0 :     for (vector<string>::const_iterator it = config.route_targets.begin();
     379           0 :         it != config.route_targets.end(); ++it) {
     380           0 :         error_code ec;
     381           0 :         RouteTarget rtarget = RouteTarget::FromString(*it, &ec);
     382           0 :         if (ec.failed())
     383           0 :             continue;
     384           0 :         rtarget_list_.insert(rtarget);
     385             :     }
     386           0 :     community_ = GetCommunity(config);
     387           0 : }
     388             : 
     389             : // RemoveStaticRoute
     390             : template <typename T>
     391           0 : void StaticRoute<T>::RemoveStaticRoute() {
     392           0 :     CHECK_CONCURRENCY("bgp::StaticRoute");
     393           0 :     RouteT rt_key(prefix_);
     394             :     DBTablePartition *partition =
     395           0 :        static_cast<DBTablePartition *>(bgp_table()->GetTablePartition(&rt_key));
     396             :     BgpRoute *static_route =
     397           0 :         static_cast<BgpRoute *>(partition->Find(&rt_key));
     398           0 :     if (!static_route || static_route->IsDeleted()) return;
     399             : 
     400           0 :     for (NexthopPathIdList::iterator it = NexthopPathIds()->begin();
     401           0 :          it != NexthopPathIds()->end(); it++) {
     402           0 :         static_route->RemovePath(BgpPath::StaticRoute, NULL, *it);
     403           0 :         BGP_LOG_STR(BgpMessage, SandeshLevel::SYS_DEBUG, BGP_LOG_FLAG_TRACE,
     404             :             "Removed Static route path " << static_route->ToString() <<
     405             :             " path_id " << BgpPath::PathIdString(*it) <<
     406             :             " in table " << bgp_table()->name());
     407             :     }
     408             : 
     409           0 :     if (!static_route->HasPaths()) {
     410           0 :         partition->Delete(static_route);
     411             :     } else {
     412           0 :         partition->Notify(static_route);
     413             :     }
     414           0 : }
     415             : 
     416             : // UpdateStaticRoute
     417             : template <typename T>
     418           0 : void StaticRoute<T>::UpdateStaticRoute() {
     419           0 :     CHECK_CONCURRENCY("bgp::Config", "bgp::ConfigHelper");
     420           0 :     RouteT rt_key(prefix_);
     421             :     DBTablePartition *partition =
     422           0 :        static_cast<DBTablePartition *>(bgp_table()->GetTablePartition(&rt_key));
     423             :     BgpRoute *static_route =
     424           0 :         static_cast<BgpRoute *>(partition->Find(&rt_key));
     425           0 :     if (static_route == NULL) return;
     426             : 
     427           0 :     static_route->ClearDelete();
     428             : 
     429           0 :     BgpAttrDB *attr_db = routing_instance()->server()->attr_db();
     430           0 :     for (NexthopPathIdList::iterator it = NexthopPathIds()->begin();
     431           0 :          it != NexthopPathIds()->end(); it++) {
     432             :         BgpPath *existing_path =
     433           0 :             static_route->FindPath(BgpPath::StaticRoute, NULL, *it);
     434           0 :         BGP_LOG_STR(BgpMessage, SandeshLevel::SYS_DEBUG, BGP_LOG_FLAG_TRACE,
     435             :             "Update attributes of StaticRoute path "
     436             :             << static_route->ToString() << " path_id "
     437             :             << BgpPath::PathIdString(*it) << " in table "
     438             :             << bgp_table()->name());
     439             : 
     440             :         // Add the RouteTarget and OrignVn in the ExtCommunity attribute.
     441           0 :         ExtCommunityPtr ptr = UpdateExtCommunity(existing_path->GetAttr());
     442           0 :         BgpAttrPtr new_attr = attr_db->ReplaceExtCommunityAndLocate(
     443             :             existing_path->GetAttr(), ptr);
     444             : 
     445             :         // Use pre-calculated community from the StaticRoute.
     446           0 :         new_attr =
     447           0 :             attr_db->ReplaceCommunityAndLocate(new_attr.get(), community_);
     448             : 
     449           0 :         BgpPath *new_path =
     450           0 :             new BgpPath(*it, BgpPath::StaticRoute, new_attr.get(),
     451           0 :                         existing_path->GetFlags(), existing_path->GetLabel());
     452             : 
     453           0 :         static_route->RemovePath(BgpPath::StaticRoute, NULL, *it);
     454             : 
     455           0 :         static_route->InsertPath(new_path);
     456             :     }
     457           0 :     partition->Notify(static_route);
     458           0 : }
     459             : 
     460             : // AddStaticRoute
     461             : template <typename T>
     462           0 : void StaticRoute<T>::AddStaticRoute(NexthopPathIdList *old_path_ids) {
     463           0 :     CHECK_CONCURRENCY("bgp::StaticRoute");
     464             : 
     465           0 :     RouteT rt_key(prefix_);
     466             :     DBTablePartition *partition =
     467           0 :        static_cast<DBTablePartition *>(bgp_table()->GetTablePartition(&rt_key));
     468             :     BgpRoute *static_route =
     469           0 :         static_cast<BgpRoute *>(partition->Find(&rt_key));
     470             : 
     471           0 :     if (static_route == NULL) {
     472           0 :         static_route = new RouteT(prefix_);
     473           0 :         partition->Add(static_route);
     474             :     } else {
     475           0 :         static_route->ClearDelete();
     476             :     }
     477             : 
     478           0 :     BgpAttrDB *attr_db = routing_instance()->server()->attr_db();
     479           0 :     for (Route::PathList::iterator it = nexthop_route()->GetPathList().begin();
     480           0 :          it != nexthop_route()->GetPathList().end(); it++) {
     481           0 :         BgpPath *nexthop_route_path = static_cast<BgpPath *>(it.operator->());
     482             : 
     483             :         // Infeasible paths are not considered
     484           0 :         if (!nexthop_route_path->IsFeasible()) break;
     485             : 
     486             :         // take snapshot of all ECMP paths
     487           0 :         if (nexthop_route()->BestPath()->PathCompare(*nexthop_route_path, true))
     488           0 :             break;
     489             : 
     490             :         // Skip paths with duplicate forwarding information.  This ensures
     491             :         // that we generate only one path with any given next hop and label
     492             :         // when there are multiple nexthop paths from the original source
     493             :         // received via different peers e.g. directly via XMPP and via BGP.
     494           0 :         if (nexthop_route()->DuplicateForwardingPath(nexthop_route_path))
     495           0 :             continue;
     496             : 
     497             :         // Add the route target in the ExtCommunity attribute.
     498           0 :         ExtCommunityPtr ptr = UpdateExtCommunity(nexthop_route_path->GetAttr());
     499           0 :         BgpAttrPtr new_attr = attr_db->ReplaceExtCommunityAndLocate(
     500             :             nexthop_route_path->GetAttr(), ptr);
     501             : 
     502             :         // Use pre-calculated community from the static route.
     503           0 :         new_attr =
     504           0 :             attr_db->ReplaceCommunityAndLocate(new_attr.get(), community_);
     505             : 
     506             :         // Strip aspath. This is required when the nexthop route is learnt
     507             :         // via BGP.
     508           0 :         new_attr = attr_db->ReplaceAsPathAndLocate(new_attr.get(), AsPathPtr());
     509             : 
     510             :         // Replace the source rd if the nexthop path is a secondary path
     511             :         // of a primary path in the l3vpn table. Use the RD of the primary.
     512           0 :         if (nexthop_route_path->IsReplicated()) {
     513           0 :             const BgpSecondaryPath *spath =
     514             :                 static_cast<const BgpSecondaryPath *>(nexthop_route_path);
     515           0 :             const RoutingInstance *ri = spath->src_table()->routing_instance();
     516           0 :             if (ri->IsMasterRoutingInstance()) {
     517             :                 const VpnRouteT *vpn_route =
     518           0 :                     static_cast<const VpnRouteT *>(spath->src_rt());
     519           0 :                 new_attr = attr_db->ReplaceSourceRdAndLocate(new_attr.get(),
     520           0 :                     vpn_route->GetPrefix().route_distinguisher());
     521             :             }
     522             :         }
     523             : 
     524             :         // Check whether we already have a path with the associated path id.
     525           0 :         uint32_t path_id =
     526           0 :             nexthop_route_path->GetAttr()->nexthop().to_v4().to_ulong();
     527           0 :         BgpPath *existing_path = static_route->FindPath(BgpPath::StaticRoute,
     528             :                                                         NULL, path_id);
     529           0 :         if (existing_path != NULL) {
     530           0 :             if ((new_attr.get() != existing_path->GetAttr()) ||
     531           0 :                 (nexthop_route_path->GetFlags() != existing_path->GetFlags()) ||
     532           0 :                 (nexthop_route_path->GetLabel() != existing_path->GetLabel())) {
     533             :                 // Update Attributes and notify (if needed)
     534           0 :                 static_route->RemovePath(BgpPath::StaticRoute, NULL, path_id);
     535             :             } else {
     536           0 :                 continue;
     537             :             }
     538             :         }
     539             : 
     540             :         // Populate SubProtocol for StaticRoute.
     541           0 :         new_attr = attr_db->ReplaceSubProtocolAndLocate(new_attr.get(),
     542             :                     MatchProtocolToString(MatchProtocol::StaticRoute));
     543             : 
     544           0 :         BgpPath *new_path =
     545           0 :             new BgpPath(path_id, BgpPath::StaticRoute, new_attr.get(),
     546           0 :                 nexthop_route_path->GetFlags(), nexthop_route_path->GetLabel());
     547           0 :         static_route->InsertPath(new_path);
     548           0 :         partition->Notify(static_route);
     549             : 
     550           0 :         BGP_LOG_STR(BgpMessage, SandeshLevel::SYS_DEBUG, BGP_LOG_FLAG_TRACE,
     551             :             "Added Static Route path " << static_route->ToString() <<
     552             :             " path_id " << BgpPath::PathIdString(path_id) <<
     553             :             " in table " << bgp_table()->name());
     554             :     }
     555             : 
     556           0 :     if (!old_path_ids) return;
     557             : 
     558           0 :     for (NexthopPathIdList::iterator it = old_path_ids->begin();
     559           0 :          it != old_path_ids->end(); it++) {
     560           0 :         if (NexthopPathIds()->find(*it) != NexthopPathIds()->end())
     561           0 :             continue;
     562           0 :         static_route->RemovePath(BgpPath::StaticRoute, NULL, *it);
     563           0 :         partition->Notify(static_route);
     564             : 
     565           0 :         BGP_LOG_STR(BgpMessage, SandeshLevel::SYS_DEBUG, BGP_LOG_FLAG_TRACE,
     566             :             "Removed StaticRoute path " << static_route->ToString() <<
     567             :             " path_id " << BgpPath::PathIdString(*it) <<
     568             :             " in table " << bgp_table()->name());
     569             :     }
     570           0 : }
     571             : 
     572             : template <typename T>
     573           0 : void StaticRoute<T>::NotifyRoute() {
     574           0 :     RouteT rt_key(prefix_);
     575             :     DBTablePartition *partition =
     576           0 :        static_cast<DBTablePartition *>(bgp_table()->GetTablePartition(&rt_key));
     577           0 :     BgpRoute *static_route = static_cast<BgpRoute *>(partition->Find(&rt_key));
     578           0 :     if (!static_route)
     579           0 :         return;
     580           0 :     partition->Notify(static_route);
     581           0 : }
     582             : 
     583             : template <typename T>
     584           0 : bool StaticRoute<T>::IsPending() const {
     585           0 :     RouteT rt_key(prefix_);
     586             :     DBTablePartition *partition =
     587           0 :        static_cast<DBTablePartition *>(bgp_table()->GetTablePartition(&rt_key));
     588           0 :     const BgpRoute *route = static_cast<BgpRoute *>(partition->Find(&rt_key));
     589           0 :     return (!route || !route->FindPath(BgpPath::StaticRoute));
     590           0 : }
     591             : 
     592             : template <>
     593             : int StaticRouteMgr<StaticRouteInet>::static_route_task_id_ = -1;
     594             : template <>
     595             : int StaticRouteMgr<StaticRouteInet6>::static_route_task_id_ = -1;
     596             : 
     597             : template <typename T>
     598           0 : StaticRouteMgr<T>::StaticRouteMgr(RoutingInstance *rtinstance)
     599           0 :     : rtinstance_(rtinstance),
     600           0 :       listener_(rtinstance_->server()->condition_listener(GetFamily())),
     601           0 :       unregister_list_trigger_(new TaskTrigger(
     602             :         boost::bind(&StaticRouteMgr::ProcessUnregisterList, this),
     603           0 :         TaskScheduler::GetInstance()->GetTaskId("bgp::Config"), 0)) {
     604           0 :     if (static_route_task_id_ == -1) {
     605           0 :         TaskScheduler *scheduler = TaskScheduler::GetInstance();
     606           0 :         static_route_task_id_ = scheduler->GetTaskId("bgp::StaticRoute");
     607             :     }
     608             : 
     609           0 :     static_route_queue_ = new WorkQueue<StaticRouteRequest *>
     610             :         (static_route_task_id_, 0,
     611             :          boost::bind(&StaticRouteMgr::StaticRouteEventCallback, this, _1));
     612           0 : }
     613             : 
     614             : template <>
     615           0 : Address::Family StaticRouteMgr<StaticRouteInet>::GetFamily() const {
     616           0 :     return Address::INET;
     617             : }
     618             : 
     619             : template <>
     620           0 : Address::Family StaticRouteMgr<StaticRouteInet6>::GetFamily() const {
     621           0 :     return Address::INET6;
     622             : }
     623             : 
     624             : template <>
     625           0 : Ip4Address StaticRouteMgr<StaticRouteInet>::GetAddress(IpAddress addr) const {
     626           0 :     assert(addr.is_v4());
     627           0 :     return addr.to_v4();
     628             : }
     629             : 
     630             : template <>
     631           0 : Ip6Address StaticRouteMgr<StaticRouteInet6>::GetAddress(IpAddress addr) const {
     632           0 :     assert(addr.is_v6());
     633           0 :     return addr.to_v6();
     634             : }
     635             : 
     636             : template <typename T>
     637           0 : void StaticRouteMgr<T>::EnqueueStaticRouteReq(StaticRouteRequest *req) {
     638           0 :     static_route_queue_->Enqueue(req);
     639           0 : }
     640             : 
     641             : template <typename T>
     642           0 : bool StaticRouteMgr<T>::StaticRouteEventCallback(StaticRouteRequest *req) {
     643           0 :     CHECK_CONCURRENCY("bgp::StaticRoute");
     644           0 :     BgpTable *table = req->table_;
     645           0 :     BgpRoute *route = req->rt_;
     646           0 :     StaticRouteT *info = static_cast<StaticRouteT *>(req->info_.get());
     647             : 
     648           0 :     StaticRouteState *state = NULL;
     649           0 :     if (route) {
     650             :         state = static_cast<StaticRouteState *>
     651           0 :             (listener_->GetMatchState(table, route, info));
     652             :     }
     653             : 
     654           0 :     switch (req->type_) {
     655           0 :         case StaticRouteRequest::NEXTHOP_ADD_CHG: {
     656           0 :             assert(state);
     657           0 :             state->reset_deleted();
     658           0 :             if (route->IsDeleted() || !route->BestPath() ||
     659           0 :                 !route->BestPath()->IsFeasible())  {
     660           0 :                 break;
     661             :             }
     662             : 
     663             :             // Store the old path list
     664           0 :             typename StaticRouteT::NexthopPathIdList path_ids;
     665           0 :             path_ids.swap(*(info->NexthopPathIds()));
     666             : 
     667             :             // Populate the Nexthop PathID
     668           0 :             info->set_nexthop_route(route);
     669             : 
     670           0 :             info->AddStaticRoute(&path_ids);
     671           0 :             break;
     672           0 :         }
     673           0 :         case StaticRouteRequest::NEXTHOP_DELETE: {
     674           0 :             assert(state);
     675           0 :             info->RemoveStaticRoute();
     676           0 :             if (info->deleted() || route->IsDeleted()) {
     677           0 :                 state->set_deleted();
     678             :             }
     679           0 :             info->set_nexthop_route(NULL);
     680           0 :             break;
     681             :         }
     682           0 :         default: {
     683           0 :             assert(0);
     684             :             break;
     685             :         }
     686             :     }
     687             : 
     688           0 :     if (state) {
     689           0 :         state->DecrementRefCnt();
     690           0 :         if (state->refcnt() == 0 && state->deleted()) {
     691           0 :             listener_->RemoveMatchState(table, route, info);
     692           0 :             delete state;
     693           0 :             if (!info->num_matchstate() && info->unregistered()) {
     694           0 :                 UnregisterAndResolveStaticRoute(info);
     695             :             }
     696             :         }
     697             :     }
     698             : 
     699           0 :     delete req;
     700           0 :     return true;
     701             : }
     702             : 
     703             : template <typename T>
     704           0 : bool StaticRouteMgr<T>::ProcessUnregisterList() {
     705           0 :     CHECK_CONCURRENCY("bgp::Config");
     706             : 
     707           0 :     for (StaticRouteProcessList::iterator
     708           0 :          it = unregister_static_route_list_.begin();
     709           0 :          it != unregister_static_route_list_.end(); ++it) {
     710           0 :         StaticRouteT *info = static_cast<StaticRouteT *>(it->get());
     711           0 :         listener_->UnregisterMatchCondition(info->bgp_table(), info);
     712           0 :         static_route_map_.erase(RouteKey(info->prefix(), info->nexthop()));
     713             :     }
     714             : 
     715           0 :     unregister_static_route_list_.clear();
     716             : 
     717           0 :     if (static_route_map_.empty()) {
     718           0 :         rtinstance_->server()->RemoveStaticRouteMgr(this);
     719             :     }
     720             : 
     721           0 :     if (!routing_instance()->deleted() &&
     722           0 :         routing_instance()->config()) {
     723           0 :         ProcessStaticRouteConfig();
     724             :     }
     725           0 :     return true;
     726             : }
     727             : 
     728             : template <typename T>
     729           0 : void StaticRouteMgr<T>::UnregisterAndResolveStaticRoute(StaticRoutePtr entry) {
     730           0 :     std::scoped_lock lock(mutex_);
     731           0 :     unregister_static_route_list_.insert(entry);
     732           0 :     unregister_list_trigger_->Set();
     733           0 : }
     734             : 
     735             : template <typename T>
     736           0 : void StaticRouteMgr<T>::LocateStaticRoutePrefix(
     737             :     const StaticRouteConfig &config) {
     738           0 :     CHECK_CONCURRENCY("bgp::Config", "bgp::ConfigHelper");
     739           0 :     AddressT address = this->GetAddress(config.address);
     740           0 :     PrefixT prefix(address, config.prefix_length);
     741           0 :     RouteKey route_key(prefix, config.nexthop);
     742             : 
     743             :     // Verify whether the entry already exists
     744           0 :     typename StaticRouteMap::iterator it = static_route_map_.find(route_key);
     745           0 :     if (it != static_route_map_.end()) {
     746             :         // Wait for the delete complete cb
     747           0 :         if (it->second->deleted()) return;
     748             : 
     749             :         StaticRouteT *match =
     750           0 :             static_cast<StaticRouteT *>(it->second.get());
     751             :         // Check whether the config has got updated
     752             :         typename StaticRouteT::CompareResult change =
     753           0 :             match->CompareConfig(config);
     754             : 
     755             :         // StaticRoutePrefix is the key, it can't change.
     756           0 :         assert(change != StaticRouteT::PrefixChange);
     757             : 
     758             :         // Skip if there's no change.
     759           0 :         if (change == StaticRouteT::NoChange)
     760           0 :             return;
     761             : 
     762             :         // Update the attributes and any existing BgpPaths.
     763           0 :         if (change == StaticRouteT::AttributeChange) {
     764           0 :             match->UpdateAttributes(config);
     765           0 :             match->UpdateStaticRoute();
     766           0 :             return;
     767             :         }
     768             : 
     769             :         // If the nexthop changes, remove the static route, if already added.
     770             :         // To do this, remove match condition and wait for remove completion.
     771           0 :         BgpConditionListener::RequestDoneCb callback =
     772             :             boost::bind(&StaticRouteMgr::StopStaticRouteDone, this, _1, _2);
     773           0 :         listener_->RemoveMatchCondition(
     774           0 :             match->bgp_table(), it->second.get(), callback);
     775           0 :         return;
     776           0 :     }
     777             : 
     778           0 :     StaticRouteT *match =
     779           0 :         new StaticRouteT(routing_instance(), this, prefix, config);
     780           0 :     StaticRoutePtr static_route_match = StaticRoutePtr(match);
     781             : 
     782           0 :     if (static_route_map_.empty())
     783           0 :         rtinstance_->server()->InsertStaticRouteMgr(this);
     784           0 :     static_route_map_.insert(make_pair(route_key, static_route_match));
     785             : 
     786           0 :     listener_->AddMatchCondition(match->bgp_table(), static_route_match.get(),
     787           0 :                                 BgpConditionListener::RequestDoneCb());
     788           0 : }
     789             : 
     790             : template <typename T>
     791           0 : void StaticRouteMgr<T>::StopStaticRouteDone(BgpTable *table,
     792             :                                              ConditionMatch *info) {
     793           0 :     CHECK_CONCURRENCY("db::Walker");
     794           0 :     StaticRoute<T> *match = static_cast<StaticRoute<T> *>(info);
     795           0 :     match->set_unregistered();
     796           0 :     if (!match->num_matchstate() && match->unregistered()) {
     797           0 :         UnregisterAndResolveStaticRoute(match);
     798             :     }
     799           0 :     return;
     800             : }
     801             : 
     802             : template <typename T>
     803           0 : void StaticRouteMgr<T>::RemoveStaticRoutePrefix(const RouteKey &static_route) {
     804           0 :     CHECK_CONCURRENCY("bgp::Config", "bgp::ConfigHelper");
     805           0 :     typename StaticRouteMap::iterator it = static_route_map_.find(static_route);
     806           0 :     if (it == static_route_map_.end()) return;
     807             : 
     808           0 :     if (it->second->deleted()) return;
     809             : 
     810           0 :     BgpConditionListener::RequestDoneCb callback =
     811             :         boost::bind(&StaticRouteMgr::StopStaticRouteDone, this, _1, _2);
     812             : 
     813           0 :     StaticRouteT *match = static_cast<StaticRouteT *>(it->second.get());
     814           0 :     listener_->RemoveMatchCondition(match->bgp_table(), match, callback);
     815           0 : }
     816             : 
     817             : template <typename T>
     818           0 : void StaticRouteMgr<T>::ProcessStaticRouteConfig() {
     819           0 :     CHECK_CONCURRENCY("bgp::Config", "bgp::ConfigHelper");
     820           0 :     if (routing_instance()->deleted() || !routing_instance()->config()) return;
     821             :     const BgpInstanceConfig::StaticRouteList &list =
     822           0 :         routing_instance()->config()->static_routes(GetFamily());
     823             :     typedef BgpInstanceConfig::StaticRouteList::const_iterator iterator_t;
     824           0 :     for (iterator_t iter = list.begin(); iter != list.end(); ++iter) {
     825           0 :         LocateStaticRoutePrefix(*iter);
     826             :     }
     827             : }
     828             : 
     829             : template <typename T>
     830           0 : StaticRouteMgr<T>::~StaticRouteMgr() {
     831           0 :     if (static_route_queue_)
     832           0 :         delete static_route_queue_;
     833           0 : }
     834             : 
     835             : template <typename T>
     836           0 : void StaticRouteMgr<T>::UpdateStaticRouteConfig() {
     837           0 :     CHECK_CONCURRENCY("bgp::Config", "bgp::ConfigHelper");
     838           0 :     StaticRouteConfigList config_list =
     839           0 :         routing_instance()->config()->static_routes(GetFamily());
     840             : 
     841           0 :     map_difference(&static_route_map_,
     842             :         config_list.begin(), config_list.end(),
     843             :         boost::bind(&StaticRouteMgr<T>::CompareStaticRoute, this, _1, _2),
     844             :         boost::bind(&StaticRouteMgr<T>::AddStaticRoute, this, _1),
     845             :         boost::bind(&StaticRouteMgr<T>::DelStaticRoute, this, _1),
     846             :         boost::bind(&StaticRouteMgr<T>::UpdateStaticRoute, this, _1, _2));
     847           0 : }
     848             : 
     849             : template <typename T>
     850           0 : void StaticRouteMgr<T>::FlushStaticRouteConfig() {
     851           0 :     CHECK_CONCURRENCY("bgp::Config");
     852           0 :     for (typename StaticRouteMap::iterator it = static_route_map_.begin();
     853           0 :          it != static_route_map_.end(); it++) {
     854           0 :         RemoveStaticRoutePrefix(it->first);
     855             :     }
     856           0 : }
     857             : 
     858             : template <typename T>
     859           0 : int StaticRouteMgr<T>::CompareStaticRoute(
     860             :     typename StaticRouteMap::iterator loc,
     861             :     StaticRouteConfigList::iterator it) {
     862           0 :     AddressT address = this->GetAddress(it->address);
     863           0 :     PrefixT prefix(address, it->prefix_length);
     864           0 :     RouteKey route_key(prefix, it->nexthop);
     865           0 :     KEY_COMPARE(loc->first, route_key);
     866           0 :     return 0;
     867             : }
     868             : 
     869             : template <typename T>
     870           0 : void StaticRouteMgr<T>::AddStaticRoute(StaticRouteConfigList::iterator it) {
     871           0 :     LocateStaticRoutePrefix(*it);
     872           0 : }
     873             : 
     874             : template <typename T>
     875           0 : void StaticRouteMgr<T>::DelStaticRoute(typename StaticRouteMap::iterator loc) {
     876           0 :     RemoveStaticRoutePrefix(loc->first);
     877           0 : }
     878             : 
     879             : template <typename T>
     880           0 : void StaticRouteMgr<T>::UpdateStaticRoute(typename StaticRouteMap::iterator loc,
     881             :     StaticRouteConfigList::iterator it) {
     882           0 :     LocateStaticRoutePrefix(*it);
     883           0 : }
     884             : 
     885             : template <typename T>
     886           0 : void StaticRouteMgr<T>::NotifyAllRoutes() {
     887           0 :     CHECK_CONCURRENCY("bgp::Config", "bgp::ConfigHelper");
     888           0 :     for (typename StaticRouteMap::iterator it = static_route_map_.begin();
     889           0 :          it != static_route_map_.end(); ++it) {
     890             :         StaticRouteT *static_route =
     891           0 :              static_cast<StaticRouteT *>(it->second.get());
     892           0 :         static_route->NotifyRoute();
     893             :     }
     894           0 : }
     895             : 
     896             : template <typename T>
     897           0 : void StaticRouteMgr<T>::UpdateAllRoutes() {
     898           0 :     CHECK_CONCURRENCY("bgp::Config", "bgp::ConfigHelper");
     899           0 :     for (typename StaticRouteMap::iterator it = static_route_map_.begin();
     900           0 :          it != static_route_map_.end(); ++it) {
     901             :         StaticRouteT *static_route =
     902           0 :              static_cast<StaticRouteT *>(it->second.get());
     903           0 :         static_route->UpdateStaticRoute();
     904             :     }
     905           0 : }
     906             : 
     907             : template <typename T>
     908           0 : void StaticRouteMgr<T>::DisableUnregisterTrigger() {
     909           0 :     unregister_list_trigger_->set_disable();
     910           0 : }
     911             : 
     912             : template <typename T>
     913           0 : void StaticRouteMgr<T>::EnableUnregisterTrigger() {
     914           0 :     unregister_list_trigger_->set_enable();
     915           0 : }
     916             : 
     917             : template <typename T>
     918           0 : uint32_t StaticRouteMgr<T>::GetRouteCount() const {
     919           0 :     CHECK_CONCURRENCY("bgp::ShowCommand");
     920           0 :     return static_route_map_.size();
     921             : }
     922             : 
     923             : template <typename T>
     924           0 : uint32_t StaticRouteMgr<T>::GetDownRouteCount() const {
     925           0 :     CHECK_CONCURRENCY("bgp::ShowCommand");
     926           0 :     uint32_t count = 0;
     927           0 :     for (typename StaticRouteMap::const_iterator it = static_route_map_.begin();
     928           0 :          it != static_route_map_.end(); ++it) {
     929             :         const StaticRouteT *static_route =
     930           0 :              static_cast<const StaticRouteT *>(it->second.get());
     931           0 :         if (static_route->IsPending())
     932           0 :             count++;
     933             :     }
     934           0 :     return count;
     935             : }
     936             : 
     937           0 : template <typename T> bool StaticRouteMgr<T>::FillStaticRouteInfo(
     938             :     RoutingInstance *ri, StaticRouteEntriesInfo *info) const {
     939           0 :     if (static_route_map_.empty())
     940           0 :         return false;
     941             : 
     942           0 :     info->set_ri_name(ri->name());
     943           0 :     for (typename StaticRouteMgr<T>::StaticRouteMap::const_iterator it =
     944           0 :          static_route_map_.begin(); it != static_route_map_.end(); ++it) {
     945             :         StaticRoute<T> *match =
     946           0 :             static_cast<StaticRoute<T> *>(it->second.get());
     947           0 :         StaticRouteInfo static_info;
     948           0 :         match->FillShowInfo(&static_info);
     949           0 :         info->static_route_list.push_back(static_info);
     950             :     }
     951           0 :     return true;
     952             : }
     953             : 
     954             : // Explicit instantiation of StaticRouteMgr for INET and INET6.
     955             : template class StaticRouteMgr<StaticRouteInet>;
     956             : template class StaticRouteMgr<StaticRouteInet6>;

Generated by: LCOV version 1.14