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: 453 477 95.0 %
Date: 2026-11-09 02:10:49 Functions: 103 105 98.1 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.14