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-06-18 01:51:13 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             :  */
       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         128 :     explicit StaticRouteState(StaticRoutePtr info) : info_(info) {
      39         128 :     }
      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        8438 :     Address::Family GetFamily() const { return manager_->GetFamily(); }
      74          60 :     AddressT GetAddress(IpAddress addr) const {
      75          60 :         return manager_->GetAddress(addr);
      76             :     }
      77             : 
      78             :     CompareResult CompareConfig(const StaticRouteConfig &config);
      79             :     void FillShowInfo(StaticRouteInfo *info) const;
      80             : 
      81         196 :     const PrefixT &prefix() const {
      82         196 :         return prefix_;
      83             :     }
      84             : 
      85         196 :     const IpAddress &nexthop() const {
      86         196 :         return nexthop_;
      87             :     }
      88             : 
      89        1116 :     RoutingInstance *routing_instance() const {
      90        1116 :         return routing_instance_;
      91             :     }
      92             : 
      93        8038 :     BgpTable *bgp_table() const {
      94        8038 :         return routing_instance_->GetTable(this->GetFamily());
      95             :     }
      96             : 
      97        1408 :     BgpRoute *nexthop_route() const {
      98        1408 :         return nexthop_route_;
      99             :     }
     100             : 
     101         981 :     NexthopPathIdList *NexthopPathIds() { return &nexthop_path_ids_; }
     102             : 
     103         354 :     void set_nexthop_route(BgpRoute *nexthop_route) {
     104         354 :         nexthop_route_ = nexthop_route;
     105             : 
     106         354 :         if (!nexthop_route_) {
     107         130 :             nexthop_path_ids_.clear();
     108         130 :             return;
     109             :         }
     110             : 
     111         224 :         assert(nexthop_path_ids_.empty());
     112             : 
     113         544 :         for (Route::PathList::iterator it =
     114         224 :              nexthop_route->GetPathList().begin();
     115        1088 :              it != nexthop_route->GetPathList().end(); it++) {
     116         320 :             BgpPath *path = static_cast<BgpPath *>(it.operator->());
     117             : 
     118             :             // Infeasible paths are not considered
     119         320 :             if (!path->IsFeasible()) break;
     120             : 
     121             :             // take snapshot of all ECMP paths
     122         320 :             if (nexthop_route_->BestPath()->PathCompare(*path, true)) break;
     123             : 
     124             :             // Use the nexthop attribute of the nexthop path as the path id.
     125         320 :             uint32_t path_id = path->GetAttr()->nexthop().to_v4().to_ulong();
     126         320 :             nexthop_path_ids_.insert(path_id);
     127             :         }
     128             :     }
     129             : 
     130        1185 :     const RouteTargetList &rtarget_list() const {
     131        1185 :         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         196 :     void set_unregistered() {
     149         196 :         unregistered_ = true;
     150         196 :     }
     151             : 
     152         686 :     bool unregistered() const {
     153         686 :         return unregistered_;
     154             :     }
     155             : 
     156             : private:
     157             :     // Helper function to match
     158        1243 :     bool is_nexthop_route(BgpRoute *route) {
     159        1243 :         RouteT *ip_route = dynamic_cast<RouteT *>(route);
     160        1243 :         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         196 : StaticRoute<T>::StaticRoute(RoutingInstance *rtinstance,
     181             :     StaticRouteMgrT *manager, const PrefixT &prefix,
     182             :     const StaticRouteConfig &config)
     183         196 :     : routing_instance_(rtinstance),
     184         196 :       manager_(manager),
     185         196 :       prefix_(prefix),
     186         196 :       nexthop_(config.nexthop),
     187         196 :       nexthop_route_(NULL),
     188         392 :       unregistered_(false) {
     189         196 :     UpdateAttributes(config);
     190         196 : }
     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          60 : typename StaticRoute<T>::CompareResult StaticRoute<T>::CompareConfig(
     198             :     const StaticRouteConfig &config) {
     199          60 :     AddressT address = this->GetAddress(config.address);
     200          60 :     PrefixT prefix(address, config.prefix_length);
     201          60 :     if (prefix_ != prefix) {
     202           0 :         return PrefixChange;
     203             :     }
     204          60 :     if (nexthop_ != config.nexthop) {
     205           0 :         return NexthopChange;
     206             :     }
     207          60 :     if (rtarget_list_.size() != config.route_targets.size()) {
     208           8 :         return AttributeChange;
     209             :     }
     210          52 :     for (vector<string>::const_iterator it = config.route_targets.begin();
     211         172 :          it != config.route_targets.end(); ++it) {
     212         122 :         error_code ec;
     213         122 :         RouteTarget rtarget = RouteTarget::FromString(*it, &ec);
     214         122 :         if (rtarget_list_.find(rtarget) == rtarget_list_.end()) {
     215           2 :             return AttributeChange;
     216             :         }
     217             :     }
     218          50 :     if (community_ != GetCommunity(config)) {
     219           2 :         return AttributeChange;
     220             :     }
     221             : 
     222          48 :     return NoChange;
     223             : }
     224             : 
     225             : template <typename T>
     226          48 : void StaticRoute<T>::FillShowInfo(StaticRouteInfo *info) const {
     227          48 :     BgpTable *table = bgp_table();
     228          48 :     RouteT rt_key(prefix_);
     229          48 :     const BgpRoute *route = static_cast<const BgpRoute *>(table->Find(&rt_key));
     230          48 :     const BgpPath *path = route ? route->FindPath(BgpPath::StaticRoute) : NULL;
     231             : 
     232          48 :     info->set_prefix(prefix_.ToString());
     233          48 :     info->set_static_rt(path ? true : false);
     234          48 :     info->set_nexthop(nexthop_.to_string());
     235          48 :     if (nexthop_route_) {
     236          38 :         ShowRouteBrief show_route;
     237          38 :         nexthop_route_->FillRouteInfo(table, &show_route);
     238          38 :         info->set_nexthop_rt(show_route);
     239          38 :     }
     240             : 
     241          48 :     vector<string> community_list;
     242         144 :     BOOST_FOREACH(uint32_t value, community_->communities()) {
     243          48 :         community_list.push_back(CommunityType::CommunityToString(value));
     244             :     }
     245          48 :     info->set_community_list(community_list);
     246             : 
     247          48 :     vector<string> route_target_list;
     248          48 :     for (RouteTargetList::const_iterator it = rtarget_list_.begin();
     249         172 :         it != rtarget_list_.end(); ++it) {
     250         124 :         route_target_list.push_back(it->ToString());
     251             :     }
     252          48 :     info->set_route_target_list(route_target_list);
     253             : 
     254          48 :     if (path) {
     255          44 :         const RoutePathReplicator *replicator = table->server()->replicator(
     256             :             Address::VpnFamilyFromFamily(GetFamily()));
     257          44 :         info->set_secondary_tables(
     258             :             replicator->GetReplicatedTableNameList(table, route, path));
     259             :     }
     260          48 : }
     261             : 
     262             : // Match function called from BgpConditionListener
     263             : // Concurrency : db::DBTable
     264             : template <typename T>
     265        1242 : bool StaticRoute<T>::Match(BgpServer *server, BgpTable *table,
     266             :                    BgpRoute *route, bool deleted) {
     267        1242 :     CHECK_CONCURRENCY("db::DBTable");
     268             :     StaticRouteRequest::RequestType type;
     269             : 
     270        1243 :     if (is_nexthop_route(route) && !unregistered()) {
     271         356 :         if (deleted)
     272         130 :             type = StaticRouteRequest::NEXTHOP_DELETE;
     273             :         else
     274         226 :             type = StaticRouteRequest::NEXTHOP_ADD_CHG;
     275             :     } else {
     276         887 :         return false;
     277             :     }
     278             : 
     279         356 :     BgpConditionListener *listener = server->condition_listener(GetFamily());
     280             :     StaticRouteState *state = static_cast<StaticRouteState *>
     281         356 :         (listener->GetMatchState(table, route, this));
     282         356 :     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         226 :         if (!state) {
     286         128 :             state = new StaticRouteState(StaticRoutePtr(this));
     287         128 :             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         130 :         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         356 :     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         712 :     StaticRouteRequest *req =
     308         356 :         new StaticRouteRequest(type, table, route, StaticRoutePtr(this));
     309         356 :     manager_->EnqueueStaticRouteReq(req);
     310             : 
     311         356 :     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         258 : CommunityPtr StaticRoute<T>::GetCommunity(const StaticRouteConfig &config) {
     321         258 :     CommunitySpec comm_spec;
     322         258 :     comm_spec.communities.push_back(CommunityType::AcceptOwnNexthop);
     323         258 :     for (vector<string>::const_iterator it = config.communities.begin();
     324         270 :          it != config.communities.end(); ++it) {
     325          12 :         uint32_t value = CommunityType::CommunityFromString(*it);
     326          12 :         if (!value)
     327           0 :             continue;
     328          12 :         comm_spec.communities.push_back(value);
     329             :     }
     330         258 :     CommunityDB *comm_db = routing_instance()->server()->comm_db();
     331         516 :     return comm_db->Locate(comm_spec);
     332         258 : }
     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         310 : ExtCommunityPtr StaticRoute<T>::UpdateExtCommunity(const BgpAttr *attr) const {
     345         310 :     ExtCommunity::ExtCommunityList export_list;
     346         310 :     for (RouteTargetList::const_iterator it = rtarget_list().begin();
     347         875 :         it != rtarget_list().end(); it++) {
     348         565 :         export_list.push_back(it->GetExtCommunity());
     349             :     }
     350             : 
     351         310 :     BgpServer *server = routing_instance()->server();
     352         310 :     ExtCommunityDB *extcomm_db = server->extcomm_db();
     353         310 :     ExtCommunityPtr new_ext_community = extcomm_db->ReplaceRTargetAndLocate(
     354             :         attr->ext_community(), export_list);
     355             : 
     356         310 :     int vn_index = routing_instance()->virtual_network_index();
     357         310 :     if (export_list.empty() && vn_index) {
     358          53 :         as_t asn = server->autonomous_system();
     359          53 :         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          53 :             OriginVn origin_vn(server->autonomous_system(), vn_index);
     368          53 :             new_ext_community = extcomm_db->ReplaceOriginVnAndLocate(
     369          53 :                 new_ext_community.get(), origin_vn.GetExtCommunity());
     370             :         }
     371             :     }
     372         620 :     return new_ext_community;
     373         310 : }
     374             : 
     375             : template <typename T>
     376         208 : void StaticRoute<T>::UpdateAttributes(const StaticRouteConfig &config) {
     377         208 :     rtarget_list_.clear();
     378         208 :     for (vector<string>::const_iterator it = config.route_targets.begin();
     379         632 :         it != config.route_targets.end(); ++it) {
     380         424 :         error_code ec;
     381         424 :         RouteTarget rtarget = RouteTarget::FromString(*it, &ec);
     382         424 :         if (ec.failed())
     383           6 :             continue;
     384         418 :         rtarget_list_.insert(rtarget);
     385             :     }
     386         208 :     community_ = GetCommunity(config);
     387         208 : }
     388             : 
     389             : // RemoveStaticRoute
     390             : template <typename T>
     391         130 : void StaticRoute<T>::RemoveStaticRoute() {
     392         130 :     CHECK_CONCURRENCY("bgp::StaticRoute");
     393         130 :     RouteT rt_key(prefix_);
     394             :     DBTablePartition *partition =
     395         130 :        static_cast<DBTablePartition *>(bgp_table()->GetTablePartition(&rt_key));
     396             :     BgpRoute *static_route =
     397         130 :         static_cast<BgpRoute *>(partition->Find(&rt_key));
     398         130 :     if (!static_route || static_route->IsDeleted()) return;
     399             : 
     400         128 :     for (NexthopPathIdList::iterator it = NexthopPathIds()->begin();
     401         261 :          it != NexthopPathIds()->end(); it++) {
     402         133 :         static_route->RemovePath(BgpPath::StaticRoute, NULL, *it);
     403         133 :         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         128 :     if (!static_route->HasPaths()) {
     410         108 :         partition->Delete(static_route);
     411             :     } else {
     412          20 :         partition->Notify(static_route);
     413             :     }
     414         130 : }
     415             : 
     416             : // UpdateStaticRoute
     417             : template <typename T>
     418          14 : void StaticRoute<T>::UpdateStaticRoute() {
     419          14 :     CHECK_CONCURRENCY("bgp::Config", "bgp::ConfigHelper");
     420          14 :     RouteT rt_key(prefix_);
     421             :     DBTablePartition *partition =
     422          14 :        static_cast<DBTablePartition *>(bgp_table()->GetTablePartition(&rt_key));
     423             :     BgpRoute *static_route =
     424          14 :         static_cast<BgpRoute *>(partition->Find(&rt_key));
     425          14 :     if (static_route == NULL) return;
     426             : 
     427          14 :     static_route->ClearDelete();
     428             : 
     429          14 :     BgpAttrDB *attr_db = routing_instance()->server()->attr_db();
     430          28 :     for (NexthopPathIdList::iterator it = NexthopPathIds()->begin();
     431          28 :          it != NexthopPathIds()->end(); it++) {
     432             :         BgpPath *existing_path =
     433          14 :             static_route->FindPath(BgpPath::StaticRoute, NULL, *it);
     434          14 :         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          14 :         ExtCommunityPtr ptr = UpdateExtCommunity(existing_path->GetAttr());
     442          14 :         BgpAttrPtr new_attr = attr_db->ReplaceExtCommunityAndLocate(
     443             :             existing_path->GetAttr(), ptr);
     444             : 
     445             :         // Use pre-calculated community from the StaticRoute.
     446          14 :         new_attr =
     447          14 :             attr_db->ReplaceCommunityAndLocate(new_attr.get(), community_);
     448             : 
     449          28 :         BgpPath *new_path =
     450          28 :             new BgpPath(*it, BgpPath::StaticRoute, new_attr.get(),
     451          14 :                         existing_path->GetFlags(), existing_path->GetLabel());
     452             : 
     453          14 :         static_route->RemovePath(BgpPath::StaticRoute, NULL, *it);
     454             : 
     455          14 :         static_route->InsertPath(new_path);
     456             :     }
     457          14 :     partition->Notify(static_route);
     458          14 : }
     459             : 
     460             : // AddStaticRoute
     461             : template <typename T>
     462         224 : void StaticRoute<T>::AddStaticRoute(NexthopPathIdList *old_path_ids) {
     463         224 :     CHECK_CONCURRENCY("bgp::StaticRoute");
     464             : 
     465         224 :     RouteT rt_key(prefix_);
     466             :     DBTablePartition *partition =
     467         224 :        static_cast<DBTablePartition *>(bgp_table()->GetTablePartition(&rt_key));
     468             :     BgpRoute *static_route =
     469         224 :         static_cast<BgpRoute *>(partition->Find(&rt_key));
     470             : 
     471         224 :     if (static_route == NULL) {
     472         124 :         static_route = new RouteT(prefix_);
     473         124 :         partition->Add(static_route);
     474             :     } else {
     475         100 :         static_route->ClearDelete();
     476             :     }
     477             : 
     478         224 :     BgpAttrDB *attr_db = routing_instance()->server()->attr_db();
     479         840 :     for (Route::PathList::iterator it = nexthop_route()->GetPathList().begin();
     480        1088 :          it != nexthop_route()->GetPathList().end(); it++) {
     481         320 :         BgpPath *nexthop_route_path = static_cast<BgpPath *>(it.operator->());
     482             : 
     483             :         // Infeasible paths are not considered
     484         320 :         if (!nexthop_route_path->IsFeasible()) break;
     485             : 
     486             :         // take snapshot of all ECMP paths
     487         320 :         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         320 :         if (nexthop_route()->DuplicateForwardingPath(nexthop_route_path))
     495          24 :             continue;
     496             : 
     497             :         // Add the route target in the ExtCommunity attribute.
     498         296 :         ExtCommunityPtr ptr = UpdateExtCommunity(nexthop_route_path->GetAttr());
     499         296 :         BgpAttrPtr new_attr = attr_db->ReplaceExtCommunityAndLocate(
     500             :             nexthop_route_path->GetAttr(), ptr);
     501             : 
     502             :         // Use pre-calculated community from the static route.
     503         296 :         new_attr =
     504         296 :             attr_db->ReplaceCommunityAndLocate(new_attr.get(), community_);
     505             : 
     506             :         // Strip aspath. This is required when the nexthop route is learnt
     507             :         // via BGP.
     508         296 :         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         296 :         if (nexthop_route_path->IsReplicated()) {
     513          77 :             const BgpSecondaryPath *spath =
     514             :                 static_cast<const BgpSecondaryPath *>(nexthop_route_path);
     515          77 :             const RoutingInstance *ri = spath->src_table()->routing_instance();
     516          77 :             if (ri->IsMasterRoutingInstance()) {
     517             :                 const VpnRouteT *vpn_route =
     518          55 :                     static_cast<const VpnRouteT *>(spath->src_rt());
     519          55 :                 new_attr = attr_db->ReplaceSourceRdAndLocate(new_attr.get(),
     520          55 :                     vpn_route->GetPrefix().route_distinguisher());
     521             :             }
     522             :         }
     523             : 
     524             :         // Check whether we already have a path with the associated path id.
     525         296 :         uint32_t path_id =
     526         296 :             nexthop_route_path->GetAttr()->nexthop().to_v4().to_ulong();
     527         296 :         BgpPath *existing_path = static_route->FindPath(BgpPath::StaticRoute,
     528             :                                                         NULL, path_id);
     529         296 :         if (existing_path != NULL) {
     530         132 :             if ((new_attr.get() != existing_path->GetAttr()) ||
     531         132 :                 (nexthop_route_path->GetFlags() != existing_path->GetFlags()) ||
     532           0 :                 (nexthop_route_path->GetLabel() != existing_path->GetLabel())) {
     533             :                 // Update Attributes and notify (if needed)
     534         132 :                 static_route->RemovePath(BgpPath::StaticRoute, NULL, path_id);
     535             :             } else {
     536           0 :                 continue;
     537             :             }
     538             :         }
     539             : 
     540             :         // Populate SubProtocol for StaticRoute.
     541         296 :         new_attr = attr_db->ReplaceSubProtocolAndLocate(new_attr.get(),
     542             :                     MatchProtocolToString(MatchProtocol::StaticRoute));
     543             : 
     544         592 :         BgpPath *new_path =
     545         296 :             new BgpPath(path_id, BgpPath::StaticRoute, new_attr.get(),
     546         296 :                 nexthop_route_path->GetFlags(), nexthop_route_path->GetLabel());
     547         296 :         static_route->InsertPath(new_path);
     548         296 :         partition->Notify(static_route);
     549             : 
     550         296 :         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         224 :     if (!old_path_ids) return;
     557             : 
     558         224 :     for (NexthopPathIdList::iterator it = old_path_ids->begin();
     559         387 :          it != old_path_ids->end(); it++) {
     560         163 :         if (NexthopPathIds()->find(*it) != NexthopPathIds()->end())
     561         132 :             continue;
     562          31 :         static_route->RemovePath(BgpPath::StaticRoute, NULL, *it);
     563          31 :         partition->Notify(static_route);
     564             : 
     565          31 :         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         224 : }
     571             : 
     572             : template <typename T>
     573        6666 : void StaticRoute<T>::NotifyRoute() {
     574        6666 :     RouteT rt_key(prefix_);
     575             :     DBTablePartition *partition =
     576        6666 :        static_cast<DBTablePartition *>(bgp_table()->GetTablePartition(&rt_key));
     577        6666 :     BgpRoute *static_route = static_cast<BgpRoute *>(partition->Find(&rt_key));
     578        6666 :     if (!static_route)
     579        6658 :         return;
     580           8 :     partition->Notify(static_route);
     581        6666 : }
     582             : 
     583             : template <typename T>
     584          24 : bool StaticRoute<T>::IsPending() const {
     585          24 :     RouteT rt_key(prefix_);
     586             :     DBTablePartition *partition =
     587          24 :        static_cast<DBTablePartition *>(bgp_table()->GetTablePartition(&rt_key));
     588          24 :     const BgpRoute *route = static_cast<BgpRoute *>(partition->Find(&rt_key));
     589          48 :     return (!route || !route->FindPath(BgpPath::StaticRoute));
     590          24 : }
     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         122 : StaticRouteMgr<T>::StaticRouteMgr(RoutingInstance *rtinstance)
     599         122 :     : rtinstance_(rtinstance),
     600         122 :       listener_(rtinstance_->server()->condition_listener(GetFamily())),
     601         244 :       unregister_list_trigger_(new TaskTrigger(
     602             :         boost::bind(&StaticRouteMgr::ProcessUnregisterList, this),
     603         488 :         TaskScheduler::GetInstance()->GetTaskId("bgp::Config"), 0)) {
     604         122 :     if (static_route_task_id_ == -1) {
     605          11 :         TaskScheduler *scheduler = TaskScheduler::GetInstance();
     606          11 :         static_route_task_id_ = scheduler->GetTaskId("bgp::StaticRoute");
     607             :     }
     608             : 
     609         122 :     static_route_queue_ = new WorkQueue<StaticRouteRequest *>
     610             :         (static_route_task_id_, 0,
     611             :          boost::bind(&StaticRouteMgr::StaticRouteEventCallback, this, _1));
     612         122 : }
     613             : 
     614             : template <>
     615        7516 : Address::Family StaticRouteMgr<StaticRouteInet>::GetFamily() const {
     616        7516 :     return Address::INET;
     617             : }
     618             : 
     619             : template <>
     620        1240 : Address::Family StaticRouteMgr<StaticRouteInet6>::GetFamily() const {
     621        1240 :     return Address::INET6;
     622             : }
     623             : 
     624             : template <>
     625         218 : Ip4Address StaticRouteMgr<StaticRouteInet>::GetAddress(IpAddress addr) const {
     626         218 :     assert(addr.is_v4());
     627         218 :     return addr.to_v4();
     628             : }
     629             : 
     630             : template <>
     631         150 : Ip6Address StaticRouteMgr<StaticRouteInet6>::GetAddress(IpAddress addr) const {
     632         150 :     assert(addr.is_v6());
     633         150 :     return addr.to_v6();
     634             : }
     635             : 
     636             : template <typename T>
     637         356 : void StaticRouteMgr<T>::EnqueueStaticRouteReq(StaticRouteRequest *req) {
     638         356 :     static_route_queue_->Enqueue(req);
     639         356 : }
     640             : 
     641             : template <typename T>
     642         356 : bool StaticRouteMgr<T>::StaticRouteEventCallback(StaticRouteRequest *req) {
     643         356 :     CHECK_CONCURRENCY("bgp::StaticRoute");
     644         356 :     BgpTable *table = req->table_;
     645         356 :     BgpRoute *route = req->rt_;
     646         356 :     StaticRouteT *info = static_cast<StaticRouteT *>(req->info_.get());
     647             : 
     648         356 :     StaticRouteState *state = NULL;
     649         356 :     if (route) {
     650             :         state = static_cast<StaticRouteState *>
     651         356 :             (listener_->GetMatchState(table, route, info));
     652             :     }
     653             : 
     654         356 :     switch (req->type_) {
     655         226 :         case StaticRouteRequest::NEXTHOP_ADD_CHG: {
     656         226 :             assert(state);
     657         226 :             state->reset_deleted();
     658         450 :             if (route->IsDeleted() || !route->BestPath() ||
     659         224 :                 !route->BestPath()->IsFeasible())  {
     660           2 :                 break;
     661             :             }
     662             : 
     663             :             // Store the old path list
     664         224 :             typename StaticRouteT::NexthopPathIdList path_ids;
     665         224 :             path_ids.swap(*(info->NexthopPathIds()));
     666             : 
     667             :             // Populate the Nexthop PathID
     668         224 :             info->set_nexthop_route(route);
     669             : 
     670         224 :             info->AddStaticRoute(&path_ids);
     671         224 :             break;
     672         224 :         }
     673         130 :         case StaticRouteRequest::NEXTHOP_DELETE: {
     674         130 :             assert(state);
     675         130 :             info->RemoveStaticRoute();
     676         130 :             if (info->deleted() || route->IsDeleted()) {
     677         130 :                 state->set_deleted();
     678             :             }
     679         130 :             info->set_nexthop_route(NULL);
     680         130 :             break;
     681             :         }
     682           0 :         default: {
     683           0 :             assert(0);
     684             :             break;
     685             :         }
     686             :     }
     687             : 
     688         356 :     if (state) {
     689         356 :         state->DecrementRefCnt();
     690         356 :         if (state->refcnt() == 0 && state->deleted()) {
     691         128 :             listener_->RemoveMatchState(table, route, info);
     692         128 :             delete state;
     693         128 :             if (!info->num_matchstate() && info->unregistered()) {
     694           2 :                 UnregisterAndResolveStaticRoute(info);
     695             :             }
     696             :         }
     697             :     }
     698             : 
     699         356 :     delete req;
     700         356 :     return true;
     701             : }
     702             : 
     703             : template <typename T>
     704         138 : bool StaticRouteMgr<T>::ProcessUnregisterList() {
     705         138 :     CHECK_CONCURRENCY("bgp::Config");
     706             : 
     707         138 :     for (StaticRouteProcessList::iterator
     708         138 :          it = unregister_static_route_list_.begin();
     709         334 :          it != unregister_static_route_list_.end(); ++it) {
     710         196 :         StaticRouteT *info = static_cast<StaticRouteT *>(it->get());
     711         196 :         listener_->UnregisterMatchCondition(info->bgp_table(), info);
     712         196 :         static_route_map_.erase(RouteKey(info->prefix(), info->nexthop()));
     713             :     }
     714             : 
     715         138 :     unregister_static_route_list_.clear();
     716             : 
     717         138 :     if (static_route_map_.empty()) {
     718         122 :         rtinstance_->server()->RemoveStaticRouteMgr(this);
     719             :     }
     720             : 
     721         160 :     if (!routing_instance()->deleted() &&
     722          22 :         routing_instance()->config()) {
     723          22 :         ProcessStaticRouteConfig();
     724             :     }
     725         138 :     return true;
     726             : }
     727             : 
     728             : template <typename T>
     729         196 : void StaticRouteMgr<T>::UnregisterAndResolveStaticRoute(StaticRoutePtr entry) {
     730         196 :     std::scoped_lock lock(mutex_);
     731         196 :     unregister_static_route_list_.insert(entry);
     732         196 :     unregister_list_trigger_->Set();
     733         196 : }
     734             : 
     735             : template <typename T>
     736         256 : void StaticRouteMgr<T>::LocateStaticRoutePrefix(
     737             :     const StaticRouteConfig &config) {
     738         256 :     CHECK_CONCURRENCY("bgp::Config", "bgp::ConfigHelper");
     739         256 :     AddressT address = this->GetAddress(config.address);
     740         256 :     PrefixT prefix(address, config.prefix_length);
     741         256 :     RouteKey route_key(prefix, config.nexthop);
     742             : 
     743             :     // Verify whether the entry already exists
     744         256 :     typename StaticRouteMap::iterator it = static_route_map_.find(route_key);
     745         256 :     if (it != static_route_map_.end()) {
     746             :         // Wait for the delete complete cb
     747          60 :         if (it->second->deleted()) return;
     748             : 
     749             :         StaticRouteT *match =
     750          60 :             static_cast<StaticRouteT *>(it->second.get());
     751             :         // Check whether the config has got updated
     752             :         typename StaticRouteT::CompareResult change =
     753          60 :             match->CompareConfig(config);
     754             : 
     755             :         // StaticRoutePrefix is the key, it can't change.
     756          60 :         assert(change != StaticRouteT::PrefixChange);
     757             : 
     758             :         // Skip if there's no change.
     759          60 :         if (change == StaticRouteT::NoChange)
     760          48 :             return;
     761             : 
     762             :         // Update the attributes and any existing BgpPaths.
     763          12 :         if (change == StaticRouteT::AttributeChange) {
     764          12 :             match->UpdateAttributes(config);
     765          12 :             match->UpdateStaticRoute();
     766          12 :             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         196 :     StaticRouteT *match =
     779         196 :         new StaticRouteT(routing_instance(), this, prefix, config);
     780         196 :     StaticRoutePtr static_route_match = StaticRoutePtr(match);
     781             : 
     782         196 :     if (static_route_map_.empty())
     783         122 :         rtinstance_->server()->InsertStaticRouteMgr(this);
     784         196 :     static_route_map_.insert(make_pair(route_key, static_route_match));
     785             : 
     786         196 :     listener_->AddMatchCondition(match->bgp_table(), static_route_match.get(),
     787         392 :                                 BgpConditionListener::RequestDoneCb());
     788         196 : }
     789             : 
     790             : template <typename T>
     791         196 : void StaticRouteMgr<T>::StopStaticRouteDone(BgpTable *table,
     792             :                                              ConditionMatch *info) {
     793         196 :     CHECK_CONCURRENCY("db::Walker");
     794         196 :     StaticRoute<T> *match = static_cast<StaticRoute<T> *>(info);
     795         196 :     match->set_unregistered();
     796         196 :     if (!match->num_matchstate() && match->unregistered()) {
     797         194 :         UnregisterAndResolveStaticRoute(match);
     798             :     }
     799         196 :     return;
     800             : }
     801             : 
     802             : template <typename T>
     803         287 : void StaticRouteMgr<T>::RemoveStaticRoutePrefix(const RouteKey &static_route) {
     804         287 :     CHECK_CONCURRENCY("bgp::Config", "bgp::ConfigHelper");
     805         287 :     typename StaticRouteMap::iterator it = static_route_map_.find(static_route);
     806         378 :     if (it == static_route_map_.end()) return;
     807             : 
     808         287 :     if (it->second->deleted()) return;
     809             : 
     810         196 :     BgpConditionListener::RequestDoneCb callback =
     811             :         boost::bind(&StaticRouteMgr::StopStaticRouteDone, this, _1, _2);
     812             : 
     813         196 :     StaticRouteT *match = static_cast<StaticRouteT *>(it->second.get());
     814         196 :     listener_->RemoveMatchCondition(match->bgp_table(), match, callback);
     815         196 : }
     816             : 
     817             : template <typename T>
     818          58 : void StaticRouteMgr<T>::ProcessStaticRouteConfig() {
     819          58 :     CHECK_CONCURRENCY("bgp::Config", "bgp::ConfigHelper");
     820          58 :     if (routing_instance()->deleted() || !routing_instance()->config()) return;
     821             :     const BgpInstanceConfig::StaticRouteList &list =
     822          58 :         routing_instance()->config()->static_routes(GetFamily());
     823             :     typedef BgpInstanceConfig::StaticRouteList::const_iterator iterator_t;
     824         158 :     for (iterator_t iter = list.begin(); iter != list.end(); ++iter) {
     825         100 :         LocateStaticRoutePrefix(*iter);
     826             :     }
     827             : }
     828             : 
     829             : template <typename T>
     830         244 : StaticRouteMgr<T>::~StaticRouteMgr() {
     831         122 :     if (static_route_queue_)
     832         122 :         delete static_route_queue_;
     833         366 : }
     834             : 
     835             : template <typename T>
     836         138 : void StaticRouteMgr<T>::UpdateStaticRouteConfig() {
     837         138 :     CHECK_CONCURRENCY("bgp::Config", "bgp::ConfigHelper");
     838         138 :     StaticRouteConfigList config_list =
     839         138 :         routing_instance()->config()->static_routes(GetFamily());
     840             : 
     841         138 :     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         138 : }
     848             : 
     849             : template <typename T>
     850         167 : void StaticRouteMgr<T>::FlushStaticRouteConfig() {
     851         167 :     CHECK_CONCURRENCY("bgp::Config");
     852         167 :     for (typename StaticRouteMap::iterator it = static_route_map_.begin();
     853         418 :          it != static_route_map_.end(); it++) {
     854         251 :         RemoveStaticRoutePrefix(it->first);
     855             :     }
     856         167 : }
     857             : 
     858             : template <typename T>
     859          52 : int StaticRouteMgr<T>::CompareStaticRoute(
     860             :     typename StaticRouteMap::iterator loc,
     861             :     StaticRouteConfigList::iterator it) {
     862          52 :     AddressT address = this->GetAddress(it->address);
     863          52 :     PrefixT prefix(address, it->prefix_length);
     864          52 :     RouteKey route_key(prefix, it->nexthop);
     865          52 :     KEY_COMPARE(loc->first, route_key);
     866          30 :     return 0;
     867             : }
     868             : 
     869             : template <typename T>
     870         126 : void StaticRouteMgr<T>::AddStaticRoute(StaticRouteConfigList::iterator it) {
     871         126 :     LocateStaticRoutePrefix(*it);
     872         126 : }
     873             : 
     874             : template <typename T>
     875          36 : void StaticRouteMgr<T>::DelStaticRoute(typename StaticRouteMap::iterator loc) {
     876          36 :     RemoveStaticRoutePrefix(loc->first);
     877          36 : }
     878             : 
     879             : template <typename T>
     880          30 : void StaticRouteMgr<T>::UpdateStaticRoute(typename StaticRouteMap::iterator loc,
     881             :     StaticRouteConfigList::iterator it) {
     882          30 :     LocateStaticRoutePrefix(*it);
     883          30 : }
     884             : 
     885             : template <typename T>
     886        3663 : void StaticRouteMgr<T>::NotifyAllRoutes() {
     887        3663 :     CHECK_CONCURRENCY("bgp::Config", "bgp::ConfigHelper");
     888        3663 :     for (typename StaticRouteMap::iterator it = static_route_map_.begin();
     889       10329 :          it != static_route_map_.end(); ++it) {
     890             :         StaticRouteT *static_route =
     891        6666 :              static_cast<StaticRouteT *>(it->second.get());
     892        6666 :         static_route->NotifyRoute();
     893             :     }
     894        3663 : }
     895             : 
     896             : template <typename T>
     897           2 : void StaticRouteMgr<T>::UpdateAllRoutes() {
     898           2 :     CHECK_CONCURRENCY("bgp::Config", "bgp::ConfigHelper");
     899           2 :     for (typename StaticRouteMap::iterator it = static_route_map_.begin();
     900           4 :          it != static_route_map_.end(); ++it) {
     901             :         StaticRouteT *static_route =
     902           2 :              static_cast<StaticRouteT *>(it->second.get());
     903           2 :         static_route->UpdateStaticRoute();
     904             :     }
     905           2 : }
     906             : 
     907             : template <typename T>
     908          12 : void StaticRouteMgr<T>::DisableUnregisterTrigger() {
     909          12 :     unregister_list_trigger_->set_disable();
     910          12 : }
     911             : 
     912             : template <typename T>
     913          12 : void StaticRouteMgr<T>::EnableUnregisterTrigger() {
     914          12 :     unregister_list_trigger_->set_enable();
     915          12 : }
     916             : 
     917             : template <typename T>
     918          40 : uint32_t StaticRouteMgr<T>::GetRouteCount() const {
     919          40 :     CHECK_CONCURRENCY("bgp::ShowCommand");
     920          40 :     return static_route_map_.size();
     921             : }
     922             : 
     923             : template <typename T>
     924           8 : uint32_t StaticRouteMgr<T>::GetDownRouteCount() const {
     925           8 :     CHECK_CONCURRENCY("bgp::ShowCommand");
     926           8 :     uint32_t count = 0;
     927           8 :     for (typename StaticRouteMap::const_iterator it = static_route_map_.begin();
     928          32 :          it != static_route_map_.end(); ++it) {
     929             :         const StaticRouteT *static_route =
     930          24 :              static_cast<const StaticRouteT *>(it->second.get());
     931          24 :         if (static_route->IsPending())
     932          16 :             count++;
     933             :     }
     934           8 :     return count;
     935             : }
     936             : 
     937          38 : template <typename T> bool StaticRouteMgr<T>::FillStaticRouteInfo(
     938             :     RoutingInstance *ri, StaticRouteEntriesInfo *info) const {
     939          38 :     if (static_route_map_.empty())
     940           0 :         return false;
     941             : 
     942          38 :     info->set_ri_name(ri->name());
     943          86 :     for (typename StaticRouteMgr<T>::StaticRouteMap::const_iterator it =
     944         124 :          static_route_map_.begin(); it != static_route_map_.end(); ++it) {
     945             :         StaticRoute<T> *match =
     946          48 :             static_cast<StaticRoute<T> *>(it->second.get());
     947          48 :         StaticRouteInfo static_info;
     948          48 :         match->FillShowInfo(&static_info);
     949          48 :         info->static_route_list.push_back(static_info);
     950             :     }
     951          38 :     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